feat: Add typecheck to the AST

This commit is contained in:
Lucàs
2024-07-05 00:06:32 +02:00
parent 0a42fbe3dc
commit d81b96779a
17 changed files with 234 additions and 39 deletions
+2
View File
@@ -1,4 +1,5 @@
open Printf
open Typecheck
let analyze lexbuf =
let ast =
@@ -19,6 +20,7 @@ let analyze lexbuf =
file_name line_num col_num "Erreur syntaxique" "Syntaxe incorrecte";
exit 1
in
let _ = type_of_source_file ast in
ast
let analyze_file file_name =
+8 -1
View File
@@ -1,3 +1,10 @@
(library
(name ast)
(modules syntax print))
(modules lexer parser syntax print typecheck analyzer)
)
(menhir
(modules parser))
(ocamllex
(modules lexer))
View File
+2 -2
View File
@@ -1,6 +1,6 @@
/* lib/parser.mly */
%{
open Ast.Syntax
open Syntax
%}
%token <int> INTEGER
@@ -103,7 +103,7 @@ unary_expression:
binary_expression:
| e1=expression "+" e2=expression { BinaryExpression(Add, e1, e2) }
| e1=expression "-" e2=expression { BinaryExpression(Substract, e1, e2) }
| e1=expression "-" e2=expression { BinaryExpression(Subtract, e1, e2) }
| e1=expression "*" e2=expression { BinaryExpression(Multiply, e1, e2) }
| e1=expression "/" e2=expression { BinaryExpression(Divide, e1, e2) }
| e1=expression "&&" e2=expression { BinaryExpression(AmpersandAmpersand, e1, e2) }
+10 -10
View File
@@ -11,10 +11,19 @@ let string_of_type = function
| BooleanType -> "BooleanType"
| VoidType -> "VoidType"
(** [string_of_literal l] returns a string representation of the literal [l]. *)
let string_of_literal = function
| Integer i -> "Integer(" ^ string_of_int i ^ ")"
| Float f -> "Float(" ^ string_of_float f ^ ")"
| Character c -> "Character('" ^ Char.escaped c ^ "')"
| String s -> "String(\"" ^ s ^ "\")"
| Boolean b -> "Boolean(" ^ string_of_bool b ^ ")"
| Null -> "Null"
(** [string_of_binary_operator op] returns a string representation of the binary operator [op]. *)
let string_of_binary_operator = function
| Add -> "Add"
| Substract -> "Substract"
| Subtract -> "Subtract"
| Multiply -> "Multiply"
| Divide -> "Divide"
| AmpersandAmpersand -> "AmpersandAmpersand"
@@ -30,15 +39,6 @@ let string_of_binary_operator = function
(** [string_of_unary_operator op] returns a string representation of the unary operator [op]. *)
let string_of_unary_operator = function Negate -> "Negate" | Not -> "Not"
(** [string_of_literal l] returns a string representation of the literal [l]. *)
let string_of_literal = function
| Integer i -> "Integer(" ^ string_of_int i ^ ")"
| Float f -> "Float(" ^ string_of_float f ^ ")"
| Character c -> "Character('" ^ Char.escaped c ^ "')"
| String s -> "String(\"" ^ s ^ "\")"
| Boolean b -> "Boolean(" ^ string_of_bool b ^ ")"
| Null -> "Null"
(** [string_of_expression e] returns a string representation of the expression [e]. *)
let rec string_of_expression = function
| Literal l -> "Literal(" ^ string_of_literal l ^ ")"
+1 -1
View File
@@ -18,7 +18,7 @@ type literal =
type binary_operator =
| Add
| Substract
| Subtract
| Multiply
| Divide
| AmpersandAmpersand
+97
View File
@@ -0,0 +1,97 @@
(* lib/ast/syntax.ml *)
open Syntax
exception Type_error of string
type environment = { variables : (string * _type) list }
(** [type_of_literal lit] returns the type of the given literal. *)
let type_of_literal (lit : literal) : _type =
match lit with
| Integer _ -> IntegerType
| Float _ -> FloatType
| Character _ -> CharacterType
| String _ -> StringType
| Boolean _ -> BooleanType
| Null -> VoidType
(** [type_of_expression env expr] returns the type of the given expression. *)
let rec type_of_expression (env : environment) (expr : expression) : _type =
match expr with
| Literal lit -> type_of_literal lit
| Identifier id -> (
try List.assoc id env.variables
with Not_found -> raise (Type_error ("Unknown variable " ^ id)))
| UnaryExpression (op, expr) -> (
let expr_type = type_of_expression env expr in
match op with
| Negate -> (
match expr_type with
| IntegerType | FloatType -> expr_type
| _ ->
raise
(Type_error "Negate operator can only be applied to numbers"))
| Not -> (
match expr_type with
| BooleanType -> BooleanType
| _ ->
raise (Type_error "Not operator can only be applied to booleans"))
)
| BinaryExpression (op, left, right) -> (
let left_type = type_of_expression env left in
let right_type = type_of_expression env right in
match op with
| Add | Subtract | Multiply | Divide -> (
match (left_type, right_type) with
| IntegerType, IntegerType -> IntegerType
| FloatType, FloatType -> FloatType
| IntegerType, FloatType | FloatType, IntegerType -> FloatType
| _ -> raise (Type_error "Arithmetic operations require numbers"))
| AmpersandAmpersand | BarBar -> (
match (left_type, right_type) with
| BooleanType, BooleanType -> BooleanType
| _ -> raise (Type_error "Logical operations require booleans"))
| EqualsEquals | ExclamationEquals -> BooleanType
| LessThan | LessThanEquals | GreaterThan | GreaterThanEquals -> (
match (left_type, right_type) with
| IntegerType, IntegerType | FloatType, FloatType -> BooleanType
| IntegerType, FloatType | FloatType, IntegerType -> BooleanType
| _ -> raise (Type_error "Comparison operations require numbers"))
| Assign -> (
match left with
| Identifier _ ->
if left_type = right_type then left_type
else raise (Type_error "Assignment requires matching types")
| _ ->
raise
(Type_error
"Assignment requires a variable on the left-hand side")))
(** [type_of_variable_declaration env var_decl] returns the environment after
processing the given variable declaration. *)
let type_of_variable_declaration (env : environment)
(VariableDeclaration (_type, id_expr, expr)) =
match id_expr with
| Identifier id ->
let expr_type = type_of_expression env expr in
if expr_type = _type then { variables = (id, _type) :: env.variables }
else
raise (Type_error ("Type mismatch in variable declaration for " ^ id))
| _ -> raise (Type_error "Variable name must be an identifier")
(** [type_of_statement env stmt] returns the environment after processing the
given statement. *)
let type_of_statement (env : environment) (stmt : statement) =
match stmt with
| ExpressionStatement expr ->
let _ = type_of_expression env expr in
env
| VariableStatement var_decls ->
List.fold_left type_of_variable_declaration env var_decls
(** [type_of_source_file (SourceFile stmts)] returns the environment after
processing the given source file. *)
let type_of_source_file (SourceFile stmts) =
let initial_env = { variables = [] } in
List.fold_left type_of_statement initial_env stmts
-17
View File
@@ -1,18 +1 @@
;lib/dune
(library
(name parser)
(modules parser)
(libraries ast))
(library
(name analyzer)
(modules lexer analyzer)
(libraries parser)
)
(menhir
(modules parser))
(ocamllex
(modules lexer))
+5
View File
@@ -0,0 +1,5 @@
; lib/eval/dune
;(library
; (name eval)
; (modules eval))
View File
View File