From 9d3fa71e3495ee1c1d345865fc48107eade16002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= <86352901+LucasVbr@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:18:17 +0200 Subject: [PATCH] feat: support variable declaration statement --- lib/ast/print.ml | 17 +++++++++++++++++ lib/ast/syntax.ml | 16 +++++++++++++++- lib/lexer.mll | 20 +++++++++++++++++--- lib/parser.mly | 29 +++++++++++++++++++++++++++++ test/ast/print.ml | 27 +++++++++++++++++++++++++++ test/ressources/test.🥐 | 26 ++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 test/ressources/test.🥐 diff --git a/lib/ast/print.ml b/lib/ast/print.ml index c6eb6f9..e326518 100644 --- a/lib/ast/print.ml +++ b/lib/ast/print.ml @@ -2,6 +2,15 @@ open Syntax +(** [string_of_type t] returns a string representation of the type [t]. *) +let string_of_type = function + | Type_Integer -> "Type_Integer" + | Type_Float -> "Type_Float" + | Type_Character -> "Type_Character" + | Type_String -> "Type_String" + | Type_Boolean -> "Type_Boolean" + | Type_Void -> "Type_Void" + (** [string_of_binary_operator op] returns a string representation of the binary operator [op]. *) let string_of_binary_operator = function | Add -> "Add" @@ -42,10 +51,18 @@ let rec string_of_expression = function ^ string_of_binary_operator op ^ ", " ^ string_of_expression e1 ^ ", " ^ string_of_expression e2 ^ ")" +let string_of_variable_declaration = function + | VariableDeclaration (t, id, e) -> + "VariableDeclaration(" ^ string_of_type t ^ ", " ^ string_of_expression id + ^ ", " ^ string_of_expression e ^ ")" + (** [string_of_statement s] returns a string representation of the statement [s]. *) let string_of_statement = function | ExpressionStatement e -> "ExpressionStatement(" ^ string_of_expression e ^ ")" + | VariableStatement decls -> + let decl_strings = List.map string_of_variable_declaration decls in + "VariableStatement([" ^ String.concat ", " decl_strings ^ "])" (** [string_of_source_file f] returns a string representation of the source file [f]. *) let string_of_source_file = function diff --git a/lib/ast/syntax.ml b/lib/ast/syntax.ml index a83cdb0..82876ed 100644 --- a/lib/ast/syntax.ml +++ b/lib/ast/syntax.ml @@ -1,5 +1,13 @@ (* lib/ast/syntax.ml *) +type _type = + | Type_Integer + | Type_Float + | Type_Character + | Type_String + | Type_Boolean + | Type_Void + type literal = | Integer of int | Float of float @@ -30,5 +38,11 @@ type expression = | UnaryExpression of unary_operator * expression | BinaryExpression of binary_operator * expression * expression -type statement = ExpressionStatement of expression +type variable_declaration = + | VariableDeclaration of _type * expression * expression + +type statement = + | ExpressionStatement of expression + | VariableStatement of variable_declaration list + type source_file = SourceFile of statement list \ No newline at end of file diff --git a/lib/lexer.mll b/lib/lexer.mll index 707ea80..bb69f77 100644 --- a/lib/lexer.mll +++ b/lib/lexer.mll @@ -5,6 +5,8 @@ } let line_comment = "//" [^ '\n']* +let block_comment = "/*" [^'.']* "*/" +let comment = line_comment | block_comment let letter = ['a'-'z' 'A'-'Z'] let digit = ['0'-'9'] @@ -18,14 +20,13 @@ let char = "'" [^'.'] "'" let string = '"' [^'.']* '"' rule token = parse - | [' ' '\t'] | line_comment { token lexbuf } + | [' ' '\t'] | comment { token lexbuf } | ['\n'] { Lexing.new_line lexbuf; token lexbuf } | '+' { PLUS } | '-' { MINUS } | '*' { TIMES } | '/' { DIVIDE } - | ';' { SEMICOLON } | "&&" { AMPERSAND_AMPERSAND } | "||" { BAR_BAR } | "==" { EQUALS_EQUALS } @@ -34,15 +35,28 @@ rule token = parse | "<=" { LESS_THAN_EQUALS } | '>' { GREATER_THAN } | ">=" { GREATER_THAN_EQUALS } + | '=' { EQUALS } | "!" { EXCLAMATION } + | ';' { SEMICOLON } + | ':' { COLON } + | ',' { COMMA } | '(' { LPAREN } | ')' { RPAREN } + | "var" { VAR } | "vrai" { BOOLEAN(true) } | "faux" { BOOLEAN(false) } - | "vide" { NULL } + | "nul" { NULL } + + | "entier" { INTEGER_TYPE } + | "reel" { FLOAT_TYPE } + | "caractere" { CHARACTER_TYPE } + | "chaine" { STRING_TYPE } + | "booleen" { BOOLEAN_TYPE } + | "vide" { VOID_TYPE } + | integer as lxm { INTEGER(int_of_string lxm) } | float as lxm { FLOAT(float_of_string lxm) } | char as lxm { CHARACTER(lxm.[1]) } diff --git a/lib/parser.mly b/lib/parser.mly index 48d069a..62ec216 100644 --- a/lib/parser.mly +++ b/lib/parser.mly @@ -11,6 +11,13 @@ %token IDENTIFIER %token NULL +%token INTEGER_TYPE +%token FLOAT_TYPE +%token CHARACTER_TYPE +%token STRING_TYPE +%token BOOLEAN_TYPE +%token VOID_TYPE + %token PLUS "+" %token MINUS "-" %token TIMES "*" @@ -24,11 +31,16 @@ %token LESS_THAN_EQUALS "<=" %token GREATER_THAN ">" %token GREATER_THAN_EQUALS ">=" +%token EQUALS "=" %token LPAREN "(" %token RPAREN ")" %token SEMICOLON ";" +%token COLON ":" +%token COMMA "," + +%token VAR "var" %token EOF @@ -52,6 +64,23 @@ statements: statement: | expression { ExpressionStatement($1) } + | "var" variable_declaration_list { VariableStatement($2) } + +variable_declaration_list: + | variable_declaration { [$1] } + | variable_declaration "," variable_declaration_list { $1 :: $3 } + +variable_declaration: + | IDENTIFIER ":" tp "=" expression { VariableDeclaration($3, Identifier($1), $5) } + | IDENTIFIER ":" tp { VariableDeclaration($3, Identifier($1), Literal(Null)) } + +tp: + | INTEGER_TYPE { Type_Integer } + | FLOAT_TYPE { Type_Float } + | CHARACTER_TYPE { Type_Character } + | STRING_TYPE { Type_String } + | BOOLEAN_TYPE { Type_Boolean } + | VOID_TYPE { Type_Void } expression: | literal { Literal($1) } diff --git a/test/ast/print.ml b/test/ast/print.ml index 623cc19..6943d12 100644 --- a/test/ast/print.ml +++ b/test/ast/print.ml @@ -4,6 +4,14 @@ open Alcotest open Ast.Syntax open Ast.Print +let test_string_of_type () = + check string "int" "Type_Integer" (string_of_type Type_Integer); + check string "float" "Type_Float" (string_of_type Type_Float); + check string "bool" "Type_Boolean" (string_of_type Type_Boolean); + check string "string" "Type_String" (string_of_type Type_String); + check string "char" "Type_Character" (string_of_type Type_Character); + check string "void" "Type_Void" (string_of_type Type_Void) + let test_string_of_literal () = check string "42" "Integer(42)" (string_of_literal (Integer 42)); check string "3.14" "Float(3.14)" (string_of_literal (Float 3.14)); @@ -50,6 +58,24 @@ let test_string_of_expression () = let test_string_of_statement () = let stmt = ExpressionStatement (Literal (Integer 42)) in check string "42;" "ExpressionStatement(Literal(Integer(42)))" + (string_of_statement stmt); + let stmt = + VariableStatement + [ VariableDeclaration (Type_Integer, Identifier "x", Literal Null) ] + in + check string "int x;" + "VariableStatement([VariableDeclaration(Type_Integer, Identifier(\"x\"), \ + Literal(Null))])" + (string_of_statement stmt); + let stmt = + VariableStatement + [ + VariableDeclaration (Type_Integer, Identifier "x", Literal (Integer 42)); + ] + in + check string "int x = 42;" + "VariableStatement([VariableDeclaration(Type_Integer, Identifier(\"x\"), \ + Literal(Integer(42)))])" (string_of_statement stmt) let test_string_of_source_file () = @@ -71,6 +97,7 @@ let () = let open Alcotest in run "AST tests" [ + ("string_of_type", [ test_case "type" `Quick test_string_of_type ]); ( "string_of_literal", [ test_case "literal" `Quick test_string_of_literal ] ); ( "string_of_unary_operator", diff --git a/test/ressources/test.🥐 b/test/ressources/test.🥐 new file mode 100644 index 0000000..46ff5cc --- /dev/null +++ b/test/ressources/test.🥐 @@ -0,0 +1,26 @@ +// Déclaration d'une variable de type entier +var a: entier = 4 + 2 + 3 * 1; + +/* +SourceFile([ + VariableStatement([ + VariableDeclaration( + Type_Integer, + Identifier("a"), + BinaryExpression( + Add, + BinaryExpression( + Add, + Literal(Integer(4) + ), + Literal(Integer(2)) + ), + BinaryExpression( + Multiply, + Literal(Integer(3)), + Literal(Integer(1)) + )) + )] + )] +) +*/ \ No newline at end of file