diff --git a/bin/dune b/bin/dune index ee564b9..a37655e 100644 --- a/bin/dune +++ b/bin/dune @@ -1,6 +1,4 @@ -;bin/dune - (executable (name main) (public_name croissant) - (libraries ast)) + (libraries Croissant)) diff --git a/bin/main.ml b/bin/main.ml index 8337915..d36a83e 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1,18 +1,23 @@ -(* bin/main.ml *) - -open Printf -open Ast - -exception Error of string - let () = - (* Array.iteri (fun i arg -> printf "%d: %s\n" i arg) Sys.argv; *) - let help_message = "Usage: croissant \n" - and args_count = Array.length Sys.argv - 1 in - if args_count >= 2 then printf "%s" help_message - else if args_count = 1 then - let file_path = Sys.argv.(1) in - let ast = Print.string_of_source_file (Analyzer.analyze_file file_path) in - printf "%s\n" ast - else raise (Error "interpreter from stdin is not implemented yet") -(* TODO: Implement interpreter from stdin *) \ No newline at end of file + let file_path = Sys.argv.(1) in + let file_stream = open_in file_path in + let lexbuf = Lexing.from_channel file_stream in + let ast = + try Analyzer.Parser.main Analyzer.Lexer.token lexbuf with + | Analyzer.Lexer.Error c -> + let file_name = lexbuf.lex_curr_p.pos_fname + and line_num = lexbuf.lex_curr_p.pos_lnum + and col_num = lexbuf.lex_curr_p.pos_cnum - lexbuf.lex_curr_p.pos_bol in + Printf.fprintf stderr "Fichier \"%s\", ligne %d, colonne %d\n%s: %s\n" + file_name line_num col_num "Erreur lexicale" + ("Caractère '" ^ String.make 1 c ^ "' inconnu"); + exit 1 + | Analyzer.Parser.Error -> + let file_name = lexbuf.lex_curr_p.pos_fname + and line_num = lexbuf.lex_curr_p.pos_lnum + and col_num = lexbuf.lex_curr_p.pos_cnum - lexbuf.lex_curr_p.pos_bol in + Printf.fprintf stderr "Fichier \"%s\", ligne %d, colonne %d\n%s: %s\n" + file_name line_num col_num "Erreur syntaxique" "Syntaxe incorrecte"; + exit 1 + in + Printf.printf "%s\n" (Syntax.SourceFiles.pp_source_files ast) \ No newline at end of file diff --git a/lib/analyzer/dune b/lib/analyzer/dune new file mode 100644 index 0000000..d209510 --- /dev/null +++ b/lib/analyzer/dune @@ -0,0 +1,10 @@ +(library + (name Analyzer) + (modules lexer parser) + (libraries Syntax)) + +(menhir + (modules parser)) + +(ocamllex + (modules lexer)) diff --git a/lib/analyzer/lexer.mll b/lib/analyzer/lexer.mll new file mode 100644 index 0000000..bc3fe10 --- /dev/null +++ b/lib/analyzer/lexer.mll @@ -0,0 +1,67 @@ +{ +open Parser +exception Error of char + +let buffer = Buffer.create 256 +} + +let white_space = [' ' '\t' '\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 interger = digit+ +let float = digit+ '.' digit+ + +rule token = parse + | white_space { token lexbuf } + | '\n' { Lexing.new_line lexbuf; token lexbuf } + + (* Comments *) + | "//" { line_comment lexbuf } + | "/*" { block_comment lexbuf } + + (* Delimiters *) + | '(' { LPAREN } + | ')' { RPAREN } + | ';' { SEMICOLON } + + (* Operators *) + | '+' { PLUS } + | '-' { MINUS } + | '*' { TIMES } + | '/' { DIV } + + (* Keywords *) + (* ... *) + + (* Literals *) + | interger as i { INT (int_of_string i) } +(* | float as f { FLOAT (float_of_string f) } *) + + (* Identifiers *) + (* ... *) + + | eof { EOF } + | _ as c { raise (Error c) } + +and string = parse + | '"' { token lexbuf } + | '\\' { Buffer.add_char buffer '\\'; string lexbuf } + | '\n' { Buffer.add_char buffer '\n'; string lexbuf } + | eof { raise (Error '"') } + | _ { Buffer.add_char buffer (Lexing.lexeme_char lexbuf 0); string lexbuf } + +and line_comment = parse + | '\n' { Lexing.new_line lexbuf; token lexbuf } + | eof { EOF } + | _ { line_comment lexbuf } + +and block_comment = parse + | "*/" { token lexbuf } + | '\n' { Lexing.new_line lexbuf; block_comment lexbuf } + | eof { EOF } + | _ { block_comment lexbuf } \ No newline at end of file diff --git a/lib/analyzer/parser.mly b/lib/analyzer/parser.mly new file mode 100644 index 0000000..14afcaf --- /dev/null +++ b/lib/analyzer/parser.mly @@ -0,0 +1,53 @@ +%{ +open Syntax +%} + +%token INT +%token PLUS "+" +%token MINUS "-" +%token TIMES "*" +%token DIV "/" + +%token SEMICOLON ";" + +%token LPAREN "(" +%token RPAREN ")" + +%token EOF + +%left PLUS MINUS +%left TIMES DIV + +%nonassoc UMINUS + +%start main + +%% + +main: + | statements EOF { SourceFiles.SourceFile $1 } + +statements: + | statement ";" { $1 } + | statement ";" statements { Statements.SequenceStatement ($1, $3) } + +statement: + | expression { Statements.ExpressionStatement($1) } + +expression: + | literal { Expressions.Literal($1) } + | unary_expression { $1 } + | binary_expression { $1 } + | "(" expression ")" { $2 } + +literal: + | INT { Literals.Integer($1) } + +unary_expression: + | "-" expression %prec UMINUS { Expressions.UnaryExpression(UnaryOperators.ArithmeticNegation, $2) } + +binary_expression: + | expression "+" expression { Expressions.BinaryExpression (BinaryOperators.Add, $1, $3) } + | expression "-" expression { Expressions.BinaryExpression (BinaryOperators.Subtract, $1, $3) } + | expression "*" expression { Expressions.BinaryExpression (BinaryOperators.Multiply, $1, $3) } + | expression "/" expression { Expressions.BinaryExpression (BinaryOperators.Divide, $1, $3) } \ No newline at end of file diff --git a/lib/analyzer/typing.ml b/lib/analyzer/typing.ml new file mode 100644 index 0000000..3ac320c --- /dev/null +++ b/lib/analyzer/typing.ml @@ -0,0 +1 @@ +type environment = { variables : (string * _type) list } \ No newline at end of file diff --git a/lib/ast/analyzer.ml b/lib/ast/analyzer.ml deleted file mode 100644 index b7be0d3..0000000 --- a/lib/ast/analyzer.ml +++ /dev/null @@ -1,30 +0,0 @@ -open Printf -open Typecheck - -let analyze lexbuf = - let ast = - try Parser.main Lexer.token lexbuf with - | Lexer.Error c -> - let file_name = lexbuf.lex_curr_p.pos_fname - and line_num = lexbuf.lex_curr_p.pos_lnum - and col_num = lexbuf.lex_curr_p.pos_cnum - lexbuf.lex_curr_p.pos_bol in - fprintf stderr "Fichier \"%s\", ligne %d, colonne %d\n%s: %s\n" - file_name line_num col_num "Erreur lexicale" - ("Caractère '" ^ String.make 1 c ^ "' inconnu"); - exit 1 - | Parser.Error -> - let file_name = lexbuf.lex_curr_p.pos_fname - and line_num = lexbuf.lex_curr_p.pos_lnum - and col_num = lexbuf.lex_curr_p.pos_cnum - lexbuf.lex_curr_p.pos_bol in - fprintf stderr "Fichier \"%s\", ligne %d, colonne %d\n%s: %s\n" - 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 = - let file_stream = open_in file_name in - let lexbuf = Lexing.from_channel file_stream in - Lexing.set_filename lexbuf file_name; - analyze lexbuf \ No newline at end of file diff --git a/lib/ast/dune b/lib/ast/dune deleted file mode 100644 index 0d3f7a8..0000000 --- a/lib/ast/dune +++ /dev/null @@ -1,10 +0,0 @@ -(library - (name ast) - (modules lexer parser syntax print typecheck analyzer) -) - -(menhir - (modules parser)) - -(ocamllex - (modules lexer)) \ No newline at end of file diff --git a/lib/ast/lexer.mll b/lib/ast/lexer.mll deleted file mode 100644 index f030599..0000000 --- a/lib/ast/lexer.mll +++ /dev/null @@ -1,90 +0,0 @@ -(* lib/lexer.mll *) -{ - open Parser - exception Error of char - - let buffer = Buffer.create 256 -} - -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+ - -rule token = parse - | ' ' | '\t' { token lexbuf } - | "/*" { block_comment lexbuf } - | "//" { line_comment lexbuf } - | '\n' { Lexing.new_line lexbuf; token lexbuf } - - | '+' { PLUS } - | '-' { MINUS } - | '*' { TIMES } - | '/' { DIVIDE } - | "&&" { AMPERSAND_AMPERSAND } - | "||" { BAR_BAR } - | "==" { EQUALS_EQUALS } - | "!=" { EXCLAMATION_EQUALS } - | '<' { LESS_THAN } - | "<=" { LESS_THAN_EQUALS } - | '>' { GREATER_THAN } - | ">=" { GREATER_THAN_EQUALS } - | '=' { EQUALS } - - | "!" { EXCLAMATION } - | ';' { SEMICOLON } - | ':' { COLON } - | ',' { COMMA } - - | '(' { LPAREN } - | ')' { RPAREN } - - | "var" { VAR } - | "vrai" { BOOLEAN(true) } - | "faux" { BOOLEAN(false) } - | "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) } - - | "'\\''" { CHARACTER '\'' } - | "'\\n'" { CHARACTER '\n' } - | "'\\t'" { CHARACTER '\t' } - | "'\\\\'" { CHARACTER '\\' } - | "'\\r'" { CHARACTER '\r' } - | "'\\b'" { CHARACTER '\b' } - | "'" [^'\\'] "'" { CHARACTER (String.get (Lexing.lexeme lexbuf) 1) } - - | "\"" { Buffer.clear buffer; string lexbuf } - | identifier as lxm { IDENTIFIER(lxm) } - - | eof { EOF } - | _ as c { raise (Error c) } - -and string = parse - | "\"" { STRING(Buffer.contents buffer)} - | "\\\"" { Buffer.add_char buffer '"'; string lexbuf } - | '\\' { Buffer.add_char buffer '\\'; string lexbuf } - | _ as c { Buffer.add_char buffer c; string lexbuf } - -and line_comment = parse - | '\n' { Lexing.new_line lexbuf; token lexbuf } - | eof { EOF } - | _ { line_comment lexbuf } - -and block_comment = parse - | "*/" { token lexbuf } - | '\n' { Lexing.new_line lexbuf; block_comment lexbuf } - | eof { EOF } - | _ { block_comment lexbuf } \ No newline at end of file diff --git a/lib/ast/parser.mly b/lib/ast/parser.mly deleted file mode 100644 index 58a8f91..0000000 --- a/lib/ast/parser.mly +++ /dev/null @@ -1,117 +0,0 @@ -/* lib/parser.mly */ -%{ - open Syntax -%} - -%token INTEGER -%token FLOAT -%token BOOLEAN -%token CHARACTER -%token STRING -%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 "*" -%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 EQUALS "=" - -%token LPAREN "(" -%token RPAREN ")" - -%token SEMICOLON ";" -%token COLON ":" -%token COMMA "," - -%token VAR "var" - -%token EOF - -%left "&&" "||" -%left "+" "-" -%left "*" "/" -%nonassoc UMINUS - -%start main -%type main - -%% - -main: - | statements EOF { SourceFile($1) } - | EOF { SourceFile([]) } - -statements: - | statement ";" { [$1] } - | statement ";" statements { $1 :: $3 } - -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 { IntegerType } - | FLOAT_TYPE { FloatType } - | CHARACTER_TYPE { CharacterType } - | STRING_TYPE { StringType } - | BOOLEAN_TYPE { BooleanType } - | VOID_TYPE { VoidType } - -expression: - | literal { Literal($1) } - | IDENTIFIER { Identifier($1) } - | unary_expression { $1 } - | binary_expression { $1 } - | "(" expression ")" { $2 } - -literal: - | INTEGER { Integer($1) } - | FLOAT { Float($1) } - | CHARACTER { Character($1) } - | STRING { String($1) } - | BOOLEAN { Boolean($1) } - | NULL { Null } - -unary_expression: - | "-" expression %prec UMINUS { UnaryExpression(Negate, $2) } - | "!" expression { UnaryExpression(Not, $2) } - -binary_expression: - | e1=expression "+" e2=expression { BinaryExpression(Add, 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) } - | 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) } - | e1=expression "=" e2=expression { BinaryExpression(Assign, e1, e2) } diff --git a/lib/ast/print.ml b/lib/ast/print.ml deleted file mode 100644 index 31c885b..0000000 --- a/lib/ast/print.ml +++ /dev/null @@ -1,84 +0,0 @@ -(* lib/ast/print.ml *) - -open Syntax - -(** [string_of_type t] returns a string representation of the type [t]. *) -let string_of_type = function - | IntegerType -> "IntegerType" - | FloatType -> "FloatType" - | CharacterType -> "CharacterType" - | StringType -> "StringType" - | 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(\"" ^ String.escaped 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" - | Subtract -> "Subtract" - | Multiply -> "Multiply" - | Divide -> "Divide" - | AmpersandAmpersand -> "AmpersandAmpersand" - | BarBar -> "BarBar" - | EqualsEquals -> "EqualsEquals" - | ExclamationEquals -> "ExclamationEquals" - | LessThan -> "LessThan" - | LessThanEquals -> "LessThanEquals" - | GreaterThan -> "GreaterThan" - | GreaterThanEquals -> "GreaterThanEquals" - | Assign -> "Assign" - -(** [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_expression e] returns a string representation of the expression [e]. *) -let rec string_of_expression = function - | Literal l -> "Literal(" ^ string_of_literal l ^ ")" - | Identifier i -> "Identifier(\"" ^ i ^ "\")" - | UnaryExpression (op, e) -> - "UnaryExpression(" - ^ string_of_unary_operator op - ^ ", " ^ string_of_expression e ^ ")" - | BinaryExpression (op, e1, e2) -> - "BinaryExpression(" - ^ 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 - | SourceFile stmts -> - let stmt_strings = List.map string_of_statement stmts in - "SourceFile([" ^ String.concat ", " stmt_strings ^ "])" - -(** The signature of the module [Print]. *) -module type Print = sig - val string_of_type : _type -> string - val string_of_binary_operator : binary_operator -> string - val string_of_unary_operator : unary_operator -> string - val string_of_literal : literal -> string - val string_of_expression : expression -> string - val string_of_variable_declaration : variable_declaration -> string - val string_of_statement : statement -> string - val string_of_source_file : source_file -> string -end \ No newline at end of file diff --git a/lib/ast/syntax.ml b/lib/ast/syntax.ml deleted file mode 100644 index e7d2b6f..0000000 --- a/lib/ast/syntax.ml +++ /dev/null @@ -1,49 +0,0 @@ -(* lib/ast/syntax.ml *) - -type _type = - | IntegerType - | FloatType - | CharacterType - | StringType - | BooleanType - | VoidType - -type literal = - | Integer of int - | Float of float - | Character of char - | String of string - | Boolean of bool - | Null - -type binary_operator = - | Add - | Subtract - | Multiply - | Divide - | AmpersandAmpersand - | BarBar - | EqualsEquals - | ExclamationEquals - | LessThan - | LessThanEquals - | GreaterThan - | GreaterThanEquals - | Assign - -type unary_operator = Negate | Not - -type expression = - | Literal of literal - | Identifier of string - | UnaryExpression of unary_operator * expression - | BinaryExpression of binary_operator * expression * 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/ast/typecheck.ml b/lib/ast/typecheck.ml deleted file mode 100644 index 8c81ccb..0000000 --- a/lib/ast/typecheck.ml +++ /dev/null @@ -1,97 +0,0 @@ -(* 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 \ No newline at end of file diff --git a/lib/dune b/lib/dune index ccc1ab2..08baaba 100644 --- a/lib/dune +++ b/lib/dune @@ -1 +1,3 @@ -;lib/dune +(library + (name Croissant) + (libraries Syntax Analyzer)) diff --git a/lib/eval/dune b/lib/eval/dune deleted file mode 100644 index ae99f68..0000000 --- a/lib/eval/dune +++ /dev/null @@ -1,5 +0,0 @@ -; lib/eval/dune - -;(library -; (name eval) -; (modules eval)) diff --git a/lib/eval/eval.ml b/lib/eval/eval.ml deleted file mode 100644 index e69de29..0000000 diff --git a/lib/interpreter.ml b/lib/interpreter.ml deleted file mode 100644 index e69de29..0000000 diff --git a/lib/syntax/BinaryOperators.ml b/lib/syntax/BinaryOperators.ml new file mode 100644 index 0000000..bf2b571 --- /dev/null +++ b/lib/syntax/BinaryOperators.ml @@ -0,0 +1,7 @@ +type binary_operators = Add | Subtract | Multiply | Divide + +let pp_binary_operators = function + | Add -> "Add" + | Subtract -> "Subtract" + | Multiply -> "Multiply" + | Divide -> "Divide" diff --git a/lib/syntax/Expressions.ml b/lib/syntax/Expressions.ml new file mode 100644 index 0000000..faf675d --- /dev/null +++ b/lib/syntax/Expressions.ml @@ -0,0 +1,21 @@ +open Literals +open UnaryOperators +open BinaryOperators + +type expressions = + | Literal of literals + | UnaryExpression of unary_operators * expressions + | BinaryExpression of binary_operators * expressions * expressions + +let rec pp_expressions = function + | Literal l -> + let pp_l = pp_literals l in + Printf.sprintf "Literal(%s)" pp_l + | UnaryExpression (op, e) -> + let pp_op = pp_unary_operators op and pp_e = pp_expressions e in + Printf.sprintf "UnaryExpression(%s, %s)" pp_op pp_e + | BinaryExpression (op, e1, e2) -> + let pp_op = pp_binary_operators op + and pp_e1 = pp_expressions e1 + and pp_e2 = pp_expressions e2 in + Printf.sprintf "BinaryExpression(%s, %s, %s)" pp_op pp_e1 pp_e2 \ No newline at end of file diff --git a/lib/syntax/Literals.ml b/lib/syntax/Literals.ml new file mode 100644 index 0000000..f9f3bf3 --- /dev/null +++ b/lib/syntax/Literals.ml @@ -0,0 +1,15 @@ +type literals = + | Integer of int + | Float of float + | Character of char + | String of string + | Boolean of bool + | Null + +let pp_literals = function + | Integer i -> Printf.sprintf "Integer(%d)" i + | Float f -> Printf.sprintf "Float(%f)" f + | Character c -> Printf.sprintf "Character('%c')" c + | String s -> Printf.sprintf "String(\"%s\")" s + | Boolean b -> Printf.sprintf "Boolean(%b)" b + | Null -> "Null" \ No newline at end of file diff --git a/lib/syntax/SourceFiles.ml b/lib/syntax/SourceFiles.ml new file mode 100644 index 0000000..ea99f83 --- /dev/null +++ b/lib/syntax/SourceFiles.ml @@ -0,0 +1,8 @@ +open Statements + +type source_files = SourceFile of statements + +let pp_source_files = function + | SourceFile stmts -> + let pp_stmt = pp_statements stmts in + Printf.sprintf "SourceFile(%s)" pp_stmt \ No newline at end of file diff --git a/lib/syntax/Statements.ml b/lib/syntax/Statements.ml new file mode 100644 index 0000000..ef12427 --- /dev/null +++ b/lib/syntax/Statements.ml @@ -0,0 +1,13 @@ +open Expressions + +type statements = + | SequenceStatement of statements * statements + | ExpressionStatement of expressions + +let rec pp_statements = function + | SequenceStatement (stmt1, stmt2) -> + let pp_stmt1 = pp_statements stmt1 and pp_stmt2 = pp_statements stmt2 in + Printf.sprintf "SequenceStatement(%s, %s)" pp_stmt1 pp_stmt2 + | ExpressionStatement expr -> + let pp_expr = pp_expressions expr in + Printf.sprintf "ExpressionStatement(%s)" pp_expr diff --git a/lib/syntax/Types.ml b/lib/syntax/Types.ml new file mode 100644 index 0000000..106c427 --- /dev/null +++ b/lib/syntax/Types.ml @@ -0,0 +1,15 @@ +type types = + | IntegerType + | FloatType + | CharacterType + | StringType + | BooleanType + | VoidType + +let pp_types = function + | IntegerType -> "IntegerType" + | FloatType -> "FloatType" + | CharacterType -> "CharacterType" + | StringType -> "StringType" + | BooleanType -> "BooleanType" + | VoidType -> "VoidType" diff --git a/lib/syntax/UnaryOperators.ml b/lib/syntax/UnaryOperators.ml new file mode 100644 index 0000000..bb6cd61 --- /dev/null +++ b/lib/syntax/UnaryOperators.ml @@ -0,0 +1,5 @@ +type unary_operators = ArithmeticNegation | LogicalNegation + +let pp_unary_operators = function + | ArithmeticNegation -> "ArithmeticNegation" + | LogicalNegation -> "LogicalNegation" diff --git a/lib/syntax/dune b/lib/syntax/dune new file mode 100644 index 0000000..d14a6c1 --- /dev/null +++ b/lib/syntax/dune @@ -0,0 +1,10 @@ +(library + (name Syntax) + (modules + Types + Literals + BinaryOperators + UnaryOperators + Expressions + Statements + SourceFiles)) diff --git a/test/ast/dune b/test/ast/dune deleted file mode 100644 index 72e23a7..0000000 --- a/test/ast/dune +++ /dev/null @@ -1,11 +0,0 @@ -;test/ast/dune - -(test - (name print) - (libraries alcotest ast) -) - -(test - (name typecheck) - (libraries alcotest ast) -) \ No newline at end of file diff --git a/test/ast/print.ml b/test/ast/print.ml deleted file mode 100644 index 940e3e5..0000000 --- a/test/ast/print.ml +++ /dev/null @@ -1,180 +0,0 @@ -(* test/ast/print.ml *) - -open Alcotest -open Ast.Syntax - -module To_test = struct - let _type = Ast.Print.string_of_type - let literal = Ast.Print.string_of_literal - let binary_operator = Ast.Print.string_of_binary_operator - let unary_operator = Ast.Print.string_of_unary_operator - let expression = Ast.Print.string_of_expression - let variable_declaration = Ast.Print.string_of_variable_declaration - let statement = Ast.Print.string_of_statement - let source_file = Ast.Print.string_of_source_file -end - -let test_string_of_type () = - let tests = - [ - ("int", "IntegerType", IntegerType); - ("float", "FloatType", FloatType); - ("char", "CharacterType", CharacterType); - ("string", "StringType", StringType); - ("bool", "BooleanType", BooleanType); - ("void", "VoidType", VoidType); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test._type actual)) - tests - -let test_string_of_literal () = - let tests = - [ - ("42", "Integer(42)", Integer 42); - ("3.14", "Float(3.14)", Float 3.14); - ("true", "Boolean(true)", Boolean true); - ("false", "Boolean(false)", Boolean false); - ("hello", "String(\"hello\")", String "hello"); - ("c", "Character('c')", Character 'c'); - ("null", "Null", Null); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.literal actual)) - tests - -let test_string_of_binary_operator () = - let tests = - [ - ("+", "Add", Add); - ("-", "Subtract", Subtract); - ("*", "Multiply", Multiply); - ("/", "Divide", Divide); - ("&&", "AmpersandAmpersand", AmpersandAmpersand); - ("||", "BarBar", BarBar); - ("==", "EqualsEquals", EqualsEquals); - ("!=", "ExclamationEquals", ExclamationEquals); - ("<", "LessThan", LessThan); - ("<=", "LessThanEquals", LessThanEquals); - (">", "GreaterThan", GreaterThan); - (">=", "GreaterThanEquals", GreaterThanEquals); - ("=", "Assign", Assign); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.binary_operator actual)) - tests - -let test_string_of_unary_operator () = - let tests = [ ("-", "Negate", Negate); ("!", "Not", Not) ] in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.unary_operator actual)) - tests - -let test_string_of_expression () = - let tests = - [ - ("42", "Literal(Integer(42))", Literal (Integer 42)); - ( "1 + 2", - "BinaryExpression(Add, Literal(Integer(1)), Literal(Integer(2)))", - BinaryExpression (Add, Literal (Integer 1), Literal (Integer 2)) ); - ( "-42", - "UnaryExpression(Negate, Literal(Integer(42)))", - UnaryExpression (Negate, Literal (Integer 42)) ); - ("x", "Identifier(\"x\")", Identifier "x"); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.expression actual)) - tests - -let test_string_of_variable_declaration () = - let tests = - [ - ( "var x: int = 42;", - "VariableDeclaration(IntegerType, Identifier(\"x\"), \ - Literal(Integer(42)))", - VariableDeclaration (IntegerType, Identifier "x", Literal (Integer 42)) - ); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.variable_declaration actual)) - tests - -let test_string_of_statement () = - let tests = - [ - ( "42;", - "ExpressionStatement(Literal(Integer(42)))", - ExpressionStatement (Literal (Integer 42)) ); - ( "var x: int;", - "VariableStatement([VariableDeclaration(IntegerType, \ - Identifier(\"x\"), Literal(Null))])", - VariableStatement - [ VariableDeclaration (IntegerType, Identifier "x", Literal Null) ] ); - ( "var x: int = 42;", - "VariableStatement([VariableDeclaration(IntegerType, \ - Identifier(\"x\"), Literal(Integer(42)))])", - VariableStatement - [ - VariableDeclaration - (IntegerType, Identifier "x", Literal (Integer 42)); - ] ); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.statement actual)) - tests - -let test_string_of_source_file () = - let tests = - [ - ( "1; 2 + 3;", - "SourceFile([ExpressionStatement(Literal(Integer(1))), \ - ExpressionStatement(BinaryExpression(Add, Literal(Integer(2)), \ - Literal(Integer(3))))])", - SourceFile - [ - ExpressionStatement (Literal (Integer 1)); - ExpressionStatement - (BinaryExpression (Add, Literal (Integer 2), Literal (Integer 3))); - ] ); - ] - in - List.iter - (fun (name, expected, actual) -> - (check string) name expected (To_test.source_file actual)) - tests - -let () = - run "ast.print" - [ - ("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", - [ test_case "unary_operator" `Quick test_string_of_unary_operator ] ); - ( "string_of_binary_operator", - [ test_case "binary_operator" `Quick test_string_of_binary_operator ] ); - ( "string_of_expression", - [ test_case "expression" `Quick test_string_of_expression ] ); - ( "string_of_variable_declaration", - [ - test_case "variable_declaration" `Quick - test_string_of_variable_declaration; - ] ); - ( "string_of_statement", - [ test_case "statement" `Quick test_string_of_statement ] ); - ( "string_of_source_file", - [ test_case "source_file" `Quick test_string_of_source_file ] ); - ] \ No newline at end of file diff --git a/test/ast/typecheck.ml b/test/ast/typecheck.ml deleted file mode 100644 index b5a43c4..0000000 --- a/test/ast/typecheck.ml +++ /dev/null @@ -1,75 +0,0 @@ -(* test/ast/typecheck.ml *) - -open Alcotest -open Ast.Syntax -open Ast.Typecheck - -let should_be_valid function_to_test tests = - List.iter - (fun (name, expected, source) -> - let actual = function_to_test source in - check (of_pp Fmt.nop) name expected actual) - tests - -let test_type_of_literal () = - let tests = - [ - ("1", IntegerType, Integer 1); - ("1.0", FloatType, Float 1.0); - ("true", BooleanType, Boolean true); - ("false", BooleanType, Boolean false); - ("\"hello\"", StringType, String "hello"); - ("'c'", CharacterType, Character 'c'); - ("null", VoidType, Null); - ] - in - should_be_valid type_of_literal tests - -let test_type_of_expression () = - let tests = - [ - ("42", IntegerType, Literal (Integer 42)); - ("foo", StringType, Identifier "foo"); - (* TODO Add tests *) - ] - and env : environment = { variables = [ ("foo", StringType) ] } in - should_be_valid (type_of_expression env) tests -(* TODO Tests errors *) - -let test_type_of_variable_declaration () = - let tests = - [ - ( "var bar: booleen = true;", - { variables = [ ("bar", BooleanType) ] }, - VariableDeclaration - (BooleanType, Identifier "bar", Literal (Boolean true)) ); - ] - and env : environment = { variables = [] } in - should_be_valid (type_of_variable_declaration env) tests -(* TODO check other case should return an error *) - -let test_type_of_statement () = - let tests = [ (* TODO Add Tests *) ] and env = { variables = [] } in - should_be_valid (type_of_statement env) tests - -let test_type_of_source_file () = - let tests = [ (* TODO Add Tests *) ] in - should_be_valid type_of_source_file tests - -let () = - run "ast.typecheck" - [ - ( "type_of_literal", - [ test_case "type_of_literal" `Quick test_type_of_literal ] ); - ( "type_of_expression", - [ test_case "type_of_expression" `Quick test_type_of_expression ] ); - ( "type_of_variable_declaration", - [ - test_case "type_of_variable_declaration" `Quick - test_type_of_variable_declaration; - ] ); - ( "type_of_statement", - [ test_case "type_of_statement" `Quick test_type_of_statement ] ); - ( "type_of_source_file", - [ test_case "type_of_source_file" `Quick test_type_of_source_file ] ); - ] \ No newline at end of file diff --git a/test/dune b/test/dune deleted file mode 100644 index d1a8ec0..0000000 --- a/test/dune +++ /dev/null @@ -1 +0,0 @@ -;test/dune \ No newline at end of file diff --git a/test/ressources/test.🥐 b/test/ressources/test.🥐 index 2e75362..ed0ba9f 100644 --- a/test/ressources/test.🥐 +++ b/test/ressources/test.🥐 @@ -1 +1,33 @@ -var a : caractere = ''; \ No newline at end of file +1 + 1; +4 * 0; + +/* + +Root( + SequenceStatement( + ExpressionStatement( + BinaryExpression( + Add, + Literal( + Integer(1) + ), + Literal( + Integer(1) + ) + ) + ), + ExpressionStatement( + BinaryExpression( + Multiply, + Literal( + Integer(4) + ), + Literal( + Integer(0) + ) + ) + ) + ) +) + +*/ \ No newline at end of file diff --git a/test/syntax/TestBinaryOperators.ml b/test/syntax/TestBinaryOperators.ml new file mode 100644 index 0000000..1346bc0 --- /dev/null +++ b/test/syntax/TestBinaryOperators.ml @@ -0,0 +1,20 @@ +open Alcotest +open Syntax.BinaryOperators + +let test_pp_binary_operators () = + let to_check = + [ + ("Should return \"Add\"", "Add", Add); + ("Should return \"Subtract\"", "Subtract", Subtract); + ("Should return \"Multiply\"", "Multiply", Multiply); + ("Should return \"Divide\"", "Divide", Divide); + ] + in + List.iter + (fun (msg, expected, actual) -> + check string msg expected (pp_binary_operators actual)) + to_check + +let tests = + ( "BinaryOperators", + [ test_case "pp_binary_operators" `Quick test_pp_binary_operators ] ) \ No newline at end of file diff --git a/test/syntax/TestExpressions.ml b/test/syntax/TestExpressions.ml new file mode 100644 index 0000000..b8ca19c --- /dev/null +++ b/test/syntax/TestExpressions.ml @@ -0,0 +1,29 @@ +open Alcotest +open Syntax + +let test_pp_expressions () = + let to_check = + [ + ( "Should return \"Literal(...)\"", + "Literal(Integer(1))", + Expressions.Literal (Literals.Integer 1) ); + ( "Should return \"UnaryExpression(...)\"", + "UnaryExpression(ArithmeticNegation, Literal(Integer(2)))", + Expressions.UnaryExpression + ( UnaryOperators.ArithmeticNegation, + Expressions.Literal (Literals.Integer 2) ) ); + ( "Should return \"BinaryExpression(...)\"", + "BinaryExpression(Add, Literal(Integer(5)), Literal(Integer(10)))", + Expressions.BinaryExpression + ( BinaryOperators.Add, + Expressions.Literal (Literals.Integer 5), + Expressions.Literal (Literals.Integer 10) ) ); + ] + in + List.iter + (fun (msg, expected, actual) -> + check string msg expected (Expressions.pp_expressions actual)) + to_check + +let tests = + ("Expressions", [ test_case "pp_expressions" `Quick test_pp_expressions ]) \ No newline at end of file diff --git a/test/syntax/TestLiterals.ml b/test/syntax/TestLiterals.ml new file mode 100644 index 0000000..75fd10a --- /dev/null +++ b/test/syntax/TestLiterals.ml @@ -0,0 +1,22 @@ +open Alcotest +open Syntax.Literals + +let test_pp_literals () = + let to_check = + [ + ("Should return \"Integer(1)\"", "Integer(1)", Integer 1); + ("Should return \"Float(1.000000)\"", "Float(1.000000)", Float 1.0); + ( "Should return \"String(\\\"Hello, World!\\\")\"", + "String(\"Hello, World!\")", + String "Hello, World!" ); + ("Should return \"Character('c')\"", "Character('c')", Character 'c'); + ("Should return \"Boolean(true)\"", "Boolean(true)", Boolean true); + ("Should return \"Boolean(false)\"", "Boolean(false)", Boolean false); + ] + in + List.iter + (fun (msg, expected, actual) -> + check string msg expected (pp_literals actual)) + to_check + +let tests = ("Literals", [ test_case "pp_literals" `Quick test_pp_literals ]) \ No newline at end of file diff --git a/test/syntax/TestSourceFiles.ml b/test/syntax/TestSourceFiles.ml new file mode 100644 index 0000000..4800822 --- /dev/null +++ b/test/syntax/TestSourceFiles.ml @@ -0,0 +1,24 @@ +open Alcotest +open Syntax + +let test_pp_source_files () = + let to_check = + [ + ( "Should return \"SourceFile(...)\"", + "SourceFile(ExpressionStatement(BinaryExpression(Add, \ + Literal(Integer(1)), Literal(Integer(2)))))", + SourceFiles.SourceFile + (Statements.ExpressionStatement + (Expressions.BinaryExpression + ( BinaryOperators.Add, + Expressions.Literal (Literals.Integer 1), + Expressions.Literal (Literals.Integer 2) ))) ); + ] + in + List.iter + (fun (name, expected, actual) -> + check string name expected (SourceFiles.pp_source_files actual)) + to_check + +let tests = + ("SourceFiles", [ test_case "pp_source_files" `Quick test_pp_source_files ]) \ No newline at end of file diff --git a/test/syntax/TestStatements.ml b/test/syntax/TestStatements.ml new file mode 100644 index 0000000..b6e866e --- /dev/null +++ b/test/syntax/TestStatements.ml @@ -0,0 +1,27 @@ +open Alcotest +open Syntax + +let test_pp_statements () = + let to_check = + [ + ( "Should return \"ExpressionStatement(...)\"", + "ExpressionStatement(Literal(Integer(1)))", + Statements.ExpressionStatement + (Expressions.Literal (Literals.Integer 1)) ); + ( "Should return \"SequenceStatement(...)\"", + "SequenceStatement(ExpressionStatement(Literal(Integer(1))), \ + ExpressionStatement(Literal(Float(1.000000))))", + Statements.SequenceStatement + ( Statements.ExpressionStatement + (Expressions.Literal (Literals.Integer 1)), + Statements.ExpressionStatement + (Expressions.Literal (Literals.Float 1.0)) ) ); + ] + in + List.iter + (fun (name, expected, actual) -> + check string name expected (Statements.pp_statements actual)) + to_check + +let tests = + ("Statements", [ test_case "pp_statements" `Quick test_pp_statements ]) \ No newline at end of file diff --git a/test/syntax/TestSyntax.ml b/test/syntax/TestSyntax.ml new file mode 100644 index 0000000..548204a --- /dev/null +++ b/test/syntax/TestSyntax.ml @@ -0,0 +1,13 @@ +open Alcotest + +let () = + run "Syntax" + [ + TestTypes.tests; + TestLiterals.tests; + TestUnaryOperators.tests; + TestBinaryOperators.tests; + TestExpressions.tests; + TestStatements.tests; + TestSourceFiles.tests; + ] \ No newline at end of file diff --git a/test/syntax/TestTypes.ml b/test/syntax/TestTypes.ml new file mode 100644 index 0000000..61ea3a9 --- /dev/null +++ b/test/syntax/TestTypes.ml @@ -0,0 +1,18 @@ +open Alcotest +open Syntax.Types + +let test_pp_types () = + let to_check = + [ + ("Should return \"IntegerType\"", "IntegerType", IntegerType); + ("Should return \"BooleanType\"", "BooleanType", BooleanType); + ("Should return \"StringType\"", "StringType", StringType); + ("Should return \"CharacterType\"", "CharacterType", CharacterType); + ("Should return \"VoidType\"", "VoidType", VoidType); + ] + in + List.iter + (fun (msg, expected, input) -> check string msg expected (pp_types input)) + to_check + +let tests = ("Types", [ test_case "pp_types" `Quick test_pp_types ]) \ No newline at end of file diff --git a/test/syntax/TestUnaryOperators.ml b/test/syntax/TestUnaryOperators.ml new file mode 100644 index 0000000..021cb1a --- /dev/null +++ b/test/syntax/TestUnaryOperators.ml @@ -0,0 +1,19 @@ +open Alcotest +open Syntax.UnaryOperators + +let test_pp_unary_operators () = + let to_check = + [ + ( "Should return \"ArithmeticNegation\"", + ArithmeticNegation, + "ArithmeticNegation" ); + ] + in + List.iter + (fun (msg, unary_operator, expected) -> + check string msg expected (pp_unary_operators unary_operator)) + to_check + +let tests = + ( "UnaryOperators", + [ test_case "pp_unary_operators" `Quick test_pp_unary_operators ] ) \ No newline at end of file diff --git a/test/syntax/dune b/test/syntax/dune new file mode 100644 index 0000000..0a0e0a0 --- /dev/null +++ b/test/syntax/dune @@ -0,0 +1,4 @@ +(test + (name TestSyntax) + (libraries Syntax alcotest) +) \ No newline at end of file