From 69e88fd5fd356ee40c93ec57c901207bcd647f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= <86352901+LucasVbr@users.noreply.github.com> Date: Tue, 2 Jul 2024 22:35:25 +0200 Subject: [PATCH] feat: Add Literals and operator of comparison --- lib/ast/print.ml | 24 ++++++++++++++-- lib/ast/syntax.ml | 30 +++++++++++++++++--- lib/lexer.mll | 27 +++++++++++++++++- lib/parser.mly | 48 ++++++++++++++++++++++++++------ test/ast/print.ml | 71 +++++++++++++++++++++++++++++++---------------- 5 files changed, 160 insertions(+), 40 deletions(-) diff --git a/lib/ast/print.ml b/lib/ast/print.ml index 17d3048..c6eb6f9 100644 --- a/lib/ast/print.ml +++ b/lib/ast/print.ml @@ -8,13 +8,31 @@ let string_of_binary_operator = function | Substract -> "Substract" | Multiply -> "Multiply" | Divide -> "Divide" + | AmpersandAmpersand -> "AmpersandAmpersand" + | BarBar -> "BarBar" + | EqualsEquals -> "EqualsEquals" + | ExclamationEquals -> "ExclamationEquals" + | LessThan -> "LessThan" + | LessThanEquals -> "LessThanEquals" + | GreaterThan -> "GreaterThan" + | GreaterThanEquals -> "GreaterThanEquals" (** [string_of_unary_operator op] returns a string representation of the unary operator [op]. *) -let string_of_unary_operator = function Negate -> "Negate" +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 - | IntegerLiteral i -> "IntegerLiteral(" ^ string_of_int i ^ ")" + | Literal l -> "Literal(" ^ string_of_literal l ^ ")" + | Identifier i -> "Identifier(\"" ^ i ^ "\")" | UnaryExpression (op, e) -> "UnaryExpression(" ^ string_of_unary_operator op @@ -33,4 +51,4 @@ let string_of_statement = function let string_of_source_file = function | SourceFile stmts -> let stmt_strings = List.map string_of_statement stmts in - "SourceFile([" ^ String.concat ", " stmt_strings ^ "])" + "SourceFile([" ^ String.concat ", " stmt_strings ^ "])" \ No newline at end of file diff --git a/lib/ast/syntax.ml b/lib/ast/syntax.ml index 126bb37..a83cdb0 100644 --- a/lib/ast/syntax.ml +++ b/lib/ast/syntax.ml @@ -1,12 +1,34 @@ (* lib/ast/syntax.ml *) -type binary_operator = Add | Substract | Multiply | Divide -type unary_operator = Negate +type literal = + | Integer of int + | Float of float + | Character of char + | String of string + | Boolean of bool + | Null + +type binary_operator = + | Add + | Substract + | Multiply + | Divide + | AmpersandAmpersand + | BarBar + | EqualsEquals + | ExclamationEquals + | LessThan + | LessThanEquals + | GreaterThan + | GreaterThanEquals + +type unary_operator = Negate | Not type expression = - | IntegerLiteral of int + | Literal of literal + | Identifier of string | UnaryExpression of unary_operator * expression | BinaryExpression of binary_operator * expression * expression type statement = ExpressionStatement of expression -type source_file = SourceFile of statement 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 966eb6a..707ea80 100644 --- a/lib/lexer.mll +++ b/lib/lexer.mll @@ -6,8 +6,16 @@ let line_comment = "//" [^ '\n']* +let letter = ['a'-'z' 'A'-'Z'] let digit = ['0'-'9'] +let alphanum = letter | digit +let non_digit = '_' + +let identifier = letter (alphanum | non_digit)* let integer = digit+ +let float = digit* '.' digit+ +let char = "'" [^'.'] "'" +let string = '"' [^'.']* '"' rule token = parse | [' ' '\t'] | line_comment { token lexbuf } @@ -18,11 +26,28 @@ rule token = parse | '*' { TIMES } | '/' { DIVIDE } | ';' { SEMICOLON } + | "&&" { AMPERSAND_AMPERSAND } + | "||" { BAR_BAR } + | "==" { EQUALS_EQUALS } + | "!=" { EXCLAMATION_EQUALS } + | '<' { LESS_THAN } + | "<=" { LESS_THAN_EQUALS } + | '>' { GREATER_THAN } + | ">=" { GREATER_THAN_EQUALS } - | integer as lxm { INT(int_of_string lxm) } + | "!" { EXCLAMATION } | '(' { LPAREN } | ')' { RPAREN } + | "vrai" { BOOLEAN(true) } + | "faux" { BOOLEAN(false) } + | "vide" { NULL } + | integer as lxm { INTEGER(int_of_string lxm) } + | float as lxm { FLOAT(float_of_string lxm) } + | char as lxm { CHARACTER(lxm.[1]) } + | string as lxm { STRING(String.sub lxm 1 (String.length lxm - 2)) } + | identifier as lxm { IDENTIFIER(lxm) } + | eof { EOF } | _ as c { raise (Error c) } \ No newline at end of file diff --git a/lib/parser.mly b/lib/parser.mly index ae04cdf..48d069a 100644 --- a/lib/parser.mly +++ b/lib/parser.mly @@ -3,12 +3,27 @@ open Ast.Syntax %} -%token INT +%token INTEGER +%token FLOAT +%token BOOLEAN +%token CHARACTER +%token STRING +%token IDENTIFIER +%token NULL %token PLUS "+" %token MINUS "-" %token TIMES "*" %token DIVIDE "/" +%token AMPERSAND_AMPERSAND "&&" +%token BAR_BAR "||" +%token EXCLAMATION "!" +%token EQUALS_EQUALS "==" +%token EXCLAMATION_EQUALS "!=" +%token LESS_THAN "<" +%token LESS_THAN_EQUALS "<=" +%token GREATER_THAN ">" +%token GREATER_THAN_EQUALS ">=" %token LPAREN "(" %token RPAREN ")" @@ -17,6 +32,7 @@ %token EOF +%left "&&" "||" %left "+" "-" %left "*" "/" %nonassoc UMINUS @@ -28,6 +44,7 @@ main: | statements EOF { SourceFile($1) } + | EOF { SourceFile([]) } statements: | statement ";" { [$1] } @@ -37,19 +54,34 @@ statement: | expression { ExpressionStatement($1) } expression: - | literal { $1 } + | literal { Literal($1) } + | IDENTIFIER { Identifier($1) } | unary_expression { $1 } | binary_expression { $1 } | "(" expression ")" { $2 } literal: - | INT { IntegerLiteral($1) } + | INTEGER { Integer($1) } + | FLOAT { Float($1) } + | CHARACTER { Character($1) } + | STRING { String($1) } + | BOOLEAN { Boolean($1) } + | NULL { Null } unary_expression: - | MINUS expression %prec UMINUS { UnaryExpression(Negate, $2) } + | "-" expression %prec UMINUS { UnaryExpression(Negate, $2) } + | "!" expression { UnaryExpression(Not, $2) } binary_expression: - | e1=expression PLUS e2=expression { BinaryExpression(Add, e1, e2) } - | e1=expression MINUS e2=expression { BinaryExpression(Substract, e1, e2) } - | e1=expression TIMES e2=expression { BinaryExpression(Multiply, e1, e2) } - | e1=expression DIVIDE e2=expression { BinaryExpression(Divide, e1, e2) } \ No newline at end of file + | e1=expression "+" e2=expression { BinaryExpression(Add, e1, e2) } + | e1=expression "-" e2=expression { BinaryExpression(Substract, 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) } + | e1=expression "||" e2=expression { BinaryExpression(BarBar, e1, e2) } + | e1=expression "==" e2=expression { BinaryExpression(EqualsEquals, e1, e2) } + | e1=expression "!=" e2=expression { BinaryExpression(ExclamationEquals, e1, e2) } + | e1=expression "<" e2=expression { BinaryExpression(LessThan, e1, e2) } + | e1=expression "<=" e2=expression { BinaryExpression(LessThanEquals, e1, e2) } + | e1=expression ">" e2=expression { BinaryExpression(GreaterThan, e1, e2) } + | e1=expression ">=" e2=expression { BinaryExpression(GreaterThanEquals, e1, e2) } diff --git a/test/ast/print.ml b/test/ast/print.ml index 80a4e64..623cc19 100644 --- a/test/ast/print.ml +++ b/test/ast/print.ml @@ -4,60 +4,83 @@ open Alcotest open Ast.Syntax open Ast.Print +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)); + check string "true" "Boolean(true)" (string_of_literal (Boolean true)); + check string "false" "Boolean(false)" (string_of_literal (Boolean false)); + check string "hello" "String(\"hello\")" (string_of_literal (String "hello")); + check string "c" "Character('c')" (string_of_literal (Character 'c')); + check string "null" "Null" (string_of_literal Null) + let test_string_of_binary_operator () = check string "+" "Add" (string_of_binary_operator Add); check string "-" "Substract" (string_of_binary_operator Substract); check string "*" "Multiply" (string_of_binary_operator Multiply); - check string "/" "Divide" (string_of_binary_operator Divide) + check string "/" "Divide" (string_of_binary_operator Divide); + check string "&&" "AmpersandAmpersand" + (string_of_binary_operator AmpersandAmpersand); + check string "||" "BarBar" (string_of_binary_operator BarBar); + check string "==" "EqualsEquals" (string_of_binary_operator EqualsEquals); + check string "!=" "ExclamationEquals" + (string_of_binary_operator ExclamationEquals); + check string "<" "LessThan" (string_of_binary_operator LessThan); + check string "<=" "LessThanEquals" (string_of_binary_operator LessThanEquals); + check string ">" "GreaterThan" (string_of_binary_operator GreaterThan); + check string ">=" "GreaterThanEquals" + (string_of_binary_operator GreaterThanEquals) let test_string_of_unary_operator () = - check string "-" "Negate" (string_of_unary_operator Negate) + check string "-" "Negate" (string_of_unary_operator Negate); + check string "!" "Not" (string_of_unary_operator Not) let test_string_of_expression () = - let expr = BinaryExpression (Add, IntegerLiteral 1, IntegerLiteral 2) in + let expr = Literal (Integer 42) in + check string "42" "Literal(Integer(42))" (string_of_expression expr); + let expr = BinaryExpression (Add, Literal (Integer 1), Literal (Integer 2)) in check string "1 + 2" - "BinaryExpression(Add, IntegerLiteral(1), IntegerLiteral(2))" - (string_of_expression expr) + "BinaryExpression(Add, Literal(Integer(1)), Literal(Integer(2)))" + (string_of_expression expr); + let expr = UnaryExpression (Negate, Literal (Integer 42)) in + check string "-42" "UnaryExpression(Negate, Literal(Integer(42)))" + (string_of_expression expr); + let expr = Identifier "x" in + check string "x" "Identifier(\"x\")" (string_of_expression expr) let test_string_of_statement () = - let stmt = ExpressionStatement (IntegerLiteral 42) in - check string "42;" "ExpressionStatement(IntegerLiteral(42))" + let stmt = ExpressionStatement (Literal (Integer 42)) in + check string "42;" "ExpressionStatement(Literal(Integer(42)))" (string_of_statement stmt) let test_string_of_source_file () = let source_file = SourceFile [ - ExpressionStatement (IntegerLiteral 1); + ExpressionStatement (Literal (Integer 1)); ExpressionStatement - (BinaryExpression (Add, IntegerLiteral 2, IntegerLiteral 3)); + (BinaryExpression (Add, Literal (Integer 2), Literal (Integer 3))); ] in check string "1; 2 + 3;" - "SourceFile([ExpressionStatement(IntegerLiteral(1)), \ - ExpressionStatement(BinaryExpression(Add, IntegerLiteral(2), \ - IntegerLiteral(3)))])" + "SourceFile([ExpressionStatement(Literal(Integer(1))), \ + ExpressionStatement(BinaryExpression(Add, Literal(Integer(2)), \ + Literal(Integer(3))))])" (string_of_source_file source_file) let () = let open Alcotest in run "AST tests" [ + ( "string_of_literal", + [ test_case "literal" `Quick test_string_of_literal ] ); ( "string_of_unary_operator", - [ - test_case "string_of_unary_operator" `Quick - test_string_of_unary_operator; - ] ); + [ test_case "unary_operator" `Quick test_string_of_unary_operator ] ); ( "string_of_binary_operator", - [ - test_case "string_of_binary_operator" `Quick - test_string_of_binary_operator; - ] ); + [ test_case "binary_operator" `Quick test_string_of_binary_operator ] ); ( "string_of_expression", - [ test_case "string_of_expression" `Quick test_string_of_expression ] ); + [ test_case "expression" `Quick test_string_of_expression ] ); ( "string_of_statement", - [ test_case "string_of_statement" `Quick test_string_of_statement ] ); + [ test_case "statement" `Quick test_string_of_statement ] ); ( "string_of_source_file", - [ test_case "string_of_source_file" `Quick test_string_of_source_file ] - ); + [ test_case "source_file" `Quick test_string_of_source_file ] ); ] \ No newline at end of file