diff --git a/bin/main.ml b/bin/main.ml index d36a83e..3afdbd6 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1,8 +1,15 @@ +open Syntax.Roots + +let get_lexbuf () = + if Array.length Sys.argv > 1 then + let file_path = Sys.argv.(1) in + let file_stream = open_in file_path in + Lexing.from_channel file_stream + else Lexing.from_channel stdin + let () = - 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 = + let lexbuf = get_lexbuf () in + let ast : program = try Analyzer.Parser.main Analyzer.Lexer.token lexbuf with | Analyzer.Lexer.Error c -> let file_name = lexbuf.lex_curr_p.pos_fname @@ -20,4 +27,5 @@ let () = 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 + let _ = ast#check_type in + Printf.printf "%s\n" (Syntax.Literals.string_of_literal_value ast#eval) \ No newline at end of file diff --git a/lib/analyzer/dune b/lib/analyzer/dune index d209510..a905f01 100644 --- a/lib/analyzer/dune +++ b/lib/analyzer/dune @@ -1,7 +1,7 @@ (library - (name Analyzer) + (name analyzer) (modules lexer parser) - (libraries Syntax)) + (libraries syntax)) (menhir (modules parser)) diff --git a/lib/analyzer/lexer.mll b/lib/analyzer/lexer.mll index 77fe331..9a62205 100644 --- a/lib/analyzer/lexer.mll +++ b/lib/analyzer/lexer.mll @@ -33,7 +33,8 @@ rule token = parse | '+' { PLUS } | '-' { MINUS } | '*' { TIMES } - | '/' { DIV } + | '/' { DIVIDE } + | "=" { EQUAL } | "==" { EQUAL_EQUAL } | "!=" { NOT_EQUAL } | "<" { LESS_THAN } @@ -43,16 +44,24 @@ rule token = parse | "&&" { AMPERSAND_AMPERSAND } | "||" { BAR_BAR } | "!" { EXCLAMATION } + | ":" { COLON } (* Keywords *) | "vrai" { BOOLEAN(true) } | "faux" { BOOLEAN(false) } + | "var" { VAR } + | "entier" { INTEGER_TYPE } + | "flottant" { FLOAT_TYPE } + | "booleen" { BOOLEAN_TYPE } + | "chaine" { STRING_TYPE } + | "caractere" { CHARACTER_TYPE } + | "nul" { NULL_TYPE } + | "vide" { VOID_TYPE } (* Literals *) - | interger as i { INT (int_of_string i) } + | interger as i { INTEGER (int_of_string i) } | float as f { FLOAT (float_of_string f) } | '"' { Buffer.clear buffer; STRING(string lexbuf) } - | "''" { NULL } | "'\\''" { CHARACTER '\'' } | "'\\n'" { CHARACTER '\n' } | "'\\t'" { CHARACTER '\t' } diff --git a/lib/analyzer/parser.mly b/lib/analyzer/parser.mly index 42c8ea6..8dd9558 100644 --- a/lib/analyzer/parser.mly +++ b/lib/analyzer/parser.mly @@ -2,18 +2,28 @@ open Syntax %} -%token INT +%token INTEGER %token FLOAT %token CHARACTER %token BOOLEAN %token STRING %token IDENTIFIER -%token NULL + +%token EQUAL "=" +%token VAR + +%token INTEGER_TYPE +%token FLOAT_TYPE +%token BOOLEAN_TYPE +%token STRING_TYPE +%token CHARACTER_TYPE +%token NULL_TYPE +%token VOID_TYPE %token PLUS "+" %token MINUS "-" %token TIMES "*" -%token DIV "/" +%token DIVIDE "/" %token EQUAL_EQUAL "==" %token NOT_EQUAL "!=" %token LESS_THAN "<" @@ -25,6 +35,7 @@ open Syntax %token EXCLAMATION "!" %token SEMICOLON ";" +%token COLON ":" %token LPAREN "(" %token RPAREN ")" @@ -36,49 +47,59 @@ open Syntax %nonassoc UMINUS -%start main +%start main %% main: - | statements EOF { SourceFiles.SourceFile $1 } + | statements EOF { new Roots.program $1 } statements: | statement ";" { $1 } - | statement ";" statements { Statements.SequenceStatement ($1, $3) } + | statement ";" statements { new Statements.sequence $1 $3 } statement: - | expression { Statements.ExpressionStatement($1) } + | expression { new Statements.expression $1 } + | VAR IDENTIFIER ":" tp "=" expression { new Statements.variableDeclaration $2 $4 $6 } expression: - | literal { Expressions.Literal($1) } - | IDENTIFIER { Expressions.Identifier($1) } + | literal { new Expressions.literal $1 } + | IDENTIFIER { new Expressions.identifier $1 } | unary_expression { $1 } | binary_expression { $1 } | "(" expression ")" { $2 } +tp: + | INTEGER_TYPE { Types.IntegerType } + | FLOAT_TYPE { Types.FloatType } + | BOOLEAN_TYPE { Types.BooleanType } + | STRING_TYPE { Types.StringType } + | CHARACTER_TYPE { Types.CharacterType } + | NULL_TYPE { Types.NullType } + | VOID_TYPE { Types.VoidType } + literal: - | INT { Literals.Integer($1) } - | FLOAT { Literals.Float($1) } - | BOOLEAN { Literals.Boolean($1) } - | CHARACTER { Literals.Character($1) } - | STRING { Literals.String($1) } - | NULL { Literals.Null } + | INTEGER { new Literals.eInteger $1 } + | FLOAT { new Literals.eFloat $1 } + | BOOLEAN { new Literals.eBoolean $1 } + | CHARACTER { new Literals.eCharacter $1 } + | STRING { new Literals.eString $1 } + | NULL_TYPE { new Literals.eNull } unary_expression: - | "-" expression %prec UMINUS { Expressions.UnaryExpression(UnaryOperators.ArithmeticNegation, $2) } - | "!" expression { Expressions.UnaryExpression(UnaryOperators.LogicalNegation, $2) } + | "-" expression %prec UMINUS { new Expressions.unaryOperation (new UnaryOperators.arithmeticNegation) $2 } + | "!" expression { new Expressions.unaryOperation (new UnaryOperators.logicalNegation) $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) } - | expression "==" expression { Expressions.BinaryExpression (BinaryOperators.Equals, $1, $3) } - | expression "!=" expression { Expressions.BinaryExpression (BinaryOperators.NotEquals, $1, $3) } - | expression "<" expression { Expressions.BinaryExpression (BinaryOperators.LessThan, $1, $3) } - | expression "<=" expression { Expressions.BinaryExpression (BinaryOperators.LessThanEquals, $1, $3) } - | expression ">" expression { Expressions.BinaryExpression (BinaryOperators.GreaterThan, $1, $3) } - | expression ">=" expression { Expressions.BinaryExpression (BinaryOperators.GreaterThanEquals, $1, $3) } - | expression "&&" expression { Expressions.BinaryExpression (BinaryOperators.And, $1, $3) } - | expression "||" expression { Expressions.BinaryExpression (BinaryOperators.Or, $1, $3) } \ No newline at end of file + | expression "+" expression { new Expressions.binaryOperation (new BinaryOperators.add) $1 $3 } + | expression "-" expression { new Expressions.binaryOperation (new BinaryOperators.subtract) $1 $3 } + | expression "*" expression { new Expressions.binaryOperation (new BinaryOperators.multiply) $1 $3 } + | expression "/" expression { new Expressions.binaryOperation (new BinaryOperators.divide) $1 $3 } + | expression "==" expression { new Expressions.binaryOperation (new BinaryOperators.equals) $1 $3 } + | expression "!=" expression { new Expressions.binaryOperation (new BinaryOperators.notEquals) $1 $3 } + | expression "<" expression { new Expressions.binaryOperation (new BinaryOperators.lessThan) $1 $3 } + | expression "<=" expression { new Expressions.binaryOperation (new BinaryOperators.lessThanEquals) $1 $3 } + | expression ">" expression { new Expressions.binaryOperation (new BinaryOperators.greaterThan) $1 $3 } + | expression ">=" expression { new Expressions.binaryOperation (new BinaryOperators.greaterThanEquals) $1 $3 } + | expression "&&" expression { new Expressions.binaryOperation (new BinaryOperators.logicalAnd) $1 $3 } + | expression "||" expression { new Expressions.binaryOperation (new BinaryOperators.logicalOr) $1 $3 } \ No newline at end of file diff --git a/lib/analyzer/typing.ml b/lib/analyzer/typing.ml deleted file mode 100644 index c23a5fe..0000000 --- a/lib/analyzer/typing.ml +++ /dev/null @@ -1 +0,0 @@ -type environment = { variables : (string * Types.types) list } \ No newline at end of file diff --git a/lib/dune b/lib/dune index 08baaba..729160c 100644 --- a/lib/dune +++ b/lib/dune @@ -1,3 +1,3 @@ (library (name Croissant) - (libraries Syntax Analyzer)) + (libraries syntax analyzer)) diff --git a/lib/syntax/BinaryOperators.ml b/lib/syntax/BinaryOperators.ml index 7a83041..afc2343 100644 --- a/lib/syntax/BinaryOperators.ml +++ b/lib/syntax/BinaryOperators.ml @@ -1,27 +1,265 @@ -type binary_operators = - | Add - | Subtract - | Multiply - | Divide - | Equals - | NotEquals - | LessThan - | LessThanEquals - | GreaterThan - | GreaterThanEquals - | And - | Or +class virtual binaryOperator = + object + inherit Node.node + method virtual check_type : Types.t * Types.t -> Types.t -let pp_binary_operators = function - | Add -> "Add" - | Subtract -> "Subtract" - | Multiply -> "Multiply" - | Divide -> "Divide" - | Equals -> "Equals" - | NotEquals -> "NotEquals" - | LessThan -> "LessThan" - | LessThanEquals -> "LessThanEquals" - | GreaterThan -> "GreaterThan" - | GreaterThanEquals -> "GreaterThanEquals" - | And -> "And" - | Or -> "Or" \ No newline at end of file + method virtual eval + : Literals.literal_value * Literals.literal_value -> + Literals.literal_value + end + +class add = + object + inherit binaryOperator + method to_string = "Add" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.IntegerType + | Types.FloatType, Types.FloatType -> Types.FloatType + | Types.FloatType, Types.IntegerType -> Types.FloatType + | Types.IntegerType, Types.FloatType -> Types.FloatType + | Types.StringType, Types.StringType -> Types.StringType + | _ -> raise (Failure "Add: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Int (a + b) + | `Float a, `Float b -> `Float (a +. b) + | `Float a, `Int b -> `Float (a +. float_of_int b) + | `Int a, `Float b -> `Float (float_of_int a +. b) + | `String a, `String b -> `String (a ^ b) (* Concatenation *) + | _ -> raise (Failure "Add: operands must be numbers") + end + +class subtract = + object + inherit binaryOperator + method to_string = "Subtract" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.IntegerType + | Types.FloatType, Types.FloatType -> Types.FloatType + | Types.FloatType, Types.IntegerType -> Types.FloatType + | Types.IntegerType, Types.FloatType -> Types.FloatType + | _ -> raise (Failure "Subtract: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Int (a - b) + | `Float a, `Float b -> `Float (a -. b) + | `Float a, `Int b -> `Float (a -. float_of_int b) + | `Int a, `Float b -> `Float (float_of_int a -. b) + | _ -> raise (Failure "Subtract: operands must be numbers") + end + +class multiply = + object + inherit binaryOperator + method to_string = "Multiply" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.FloatType + | Types.FloatType, Types.FloatType -> Types.FloatType + | Types.FloatType, Types.IntegerType -> Types.FloatType + | Types.IntegerType, Types.FloatType -> Types.FloatType + | _ -> raise (Failure "Multiply: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Float (float_of_int a *. float_of_int b) + | `Float a, `Float b -> `Float (a *. b) + | `Float a, `Int b -> `Float (a *. float_of_int b) + | `Int a, `Float b -> `Float (float_of_int a *. b) + | _ -> raise (Failure "Multiply: operands must be numbers") + end + +class divide = + object + inherit binaryOperator + method to_string = "Divide" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.FloatType + | Types.FloatType, Types.FloatType -> Types.FloatType + | Types.FloatType, Types.IntegerType -> Types.FloatType + | Types.IntegerType, Types.FloatType -> Types.FloatType + | _ -> raise (Failure "Divide: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Float (float_of_int a /. float_of_int b) + | `Float a, `Float b -> `Float (a /. b) + | `Float a, `Int b -> `Float (a /. float_of_int b) + | `Int a, `Float b -> `Float (float_of_int a /. b) + | _ -> raise (Failure "Divide: operands must be numbers") + end + +class equals = + object + inherit binaryOperator + method to_string = "Equals" + + method check_type (left, right) = + if left = right then Types.BooleanType + else raise (Failure "Equals: operands must have the same type") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a = b) + | `Float a, `Float b -> `Bool (a = b) + | `Float a, `Int b -> `Bool (a = float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a = b) + | `String a, `String b -> `Bool (a = b) + | `Bool a, `Bool b -> `Bool (a = b) + | `Char a, `Char b -> `Bool (a = b) + | `Null, `Null -> `Bool true + | `Void, `Void -> `Bool true + | _ -> raise (Failure "Equals: operands must have the same type") + end + +class notEquals = + object + inherit binaryOperator + method to_string = "NotEquals" + + method check_type (left, right) = + if left = right then Types.BooleanType + else raise (Failure "Equals: operands must have the same type") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a <> b) + | `Float a, `Float b -> `Bool (a <> b) + | `Float a, `Int b -> `Bool (a <> float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a <> b) + | `String a, `String b -> `Bool (a <> b) + | `Bool a, `Bool b -> `Bool (a <> b) + | `Char a, `Char b -> `Bool (a <> b) + | `Null, `Null -> `Bool false + | `Void, `Void -> `Bool false + | _ -> raise (Failure "NotEquals: operands must have the same type") + end + +class lessThan = + object + inherit binaryOperator + method to_string = "LessThan" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.BooleanType + | Types.FloatType, Types.FloatType -> Types.BooleanType + | Types.FloatType, Types.IntegerType -> Types.BooleanType + | Types.IntegerType, Types.FloatType -> Types.BooleanType + | _ -> raise (Failure "LessThan: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a < b) + | `Float a, `Float b -> `Bool (a < b) + | `Float a, `Int b -> `Bool (a < float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a < b) + | _ -> raise (Failure "LessThan: operands must be numbers") + end + +class lessThanEquals = + object + inherit binaryOperator + method to_string = "LessThanEquals" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.BooleanType + | Types.FloatType, Types.FloatType -> Types.BooleanType + | Types.FloatType, Types.IntegerType -> Types.BooleanType + | Types.IntegerType, Types.FloatType -> Types.BooleanType + | _ -> raise (Failure "LessThanEquals: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a <= b) + | `Float a, `Float b -> `Bool (a <= b) + | `Float a, `Int b -> `Bool (a <= float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a <= b) + | _ -> raise (Failure "LessThanEquals: operands must be numbers") + end + +class greaterThan = + object + inherit binaryOperator + method to_string = "GreaterThan" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.BooleanType + | Types.FloatType, Types.FloatType -> Types.BooleanType + | Types.FloatType, Types.IntegerType -> Types.BooleanType + | Types.IntegerType, Types.FloatType -> Types.BooleanType + | _ -> raise (Failure "GreaterThan: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a > b) + | `Float a, `Float b -> `Bool (a > b) + | `Float a, `Int b -> `Bool (a > float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a > b) + | _ -> raise (Failure "GreaterThan: operands must be numbers") + end + +class greaterThanEquals = + object + inherit binaryOperator + method to_string = "GreaterThanEquals" + + method check_type (left, right) = + match (left, right) with + | Types.IntegerType, Types.IntegerType -> Types.BooleanType + | Types.FloatType, Types.FloatType -> Types.BooleanType + | Types.FloatType, Types.IntegerType -> Types.BooleanType + | Types.IntegerType, Types.FloatType -> Types.BooleanType + | _ -> raise (Failure "GreaterThanEquals: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Int a, `Int b -> `Bool (a >= b) + | `Float a, `Float b -> `Bool (a >= b) + | `Float a, `Int b -> `Bool (a >= float_of_int b) + | `Int a, `Float b -> `Bool (float_of_int a >= b) + | _ -> raise (Failure "GreaterThanEquals: operands must be numbers") + end + +class logicalAnd = + object + inherit binaryOperator + method to_string = "And" + + method check_type (left, right) = + match (left, right) with + | Types.BooleanType, Types.BooleanType -> Types.BooleanType + | _ -> raise (Failure "And: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Bool a, `Bool b -> `Bool (a && b) + | _ -> raise (Failure "And: operands must be booleans") + end + +class logicalOr = + object + inherit binaryOperator + method to_string = "Or" + + method check_type (left, right) = + match (left, right) with + | Types.BooleanType, Types.BooleanType -> Types.BooleanType + | _ -> raise (Failure "Or: operands must be numbers") + + method eval (left, right) = + match (left, right) with + | `Bool a, `Bool b -> `Bool (a || b) + | _ -> raise (Failure "Or: operands must be booleans") + end \ No newline at end of file diff --git a/lib/syntax/Environments.ml b/lib/syntax/Environments.ml new file mode 100644 index 0000000..7d01583 --- /dev/null +++ b/lib/syntax/Environments.ml @@ -0,0 +1,27 @@ +class evalEnvironment = + object + val mutable env : (string, Literals.literal_value) Hashtbl.t = + Hashtbl.create 10 + + method add (name : string) (lit : Literals.literal_value) = + Hashtbl.add env name lit + + method find (name : string) = Hashtbl.find env name + + method clone : evalEnvironment = + let new_env = new evalEnvironment in + Hashtbl.iter (fun k v -> new_env#add k v) env; + new_env + end + +class typeEnvironments = + object + val mutable env : (string, Types.t) Hashtbl.t = Hashtbl.create 10 + method add (name : string) (tp : Types.t) = Hashtbl.add env name tp + method find (name : string) = Hashtbl.find env name + + method clone : typeEnvironments = + let new_env = new typeEnvironments in + Hashtbl.iter (fun k v -> new_env#add k v) env; + new_env + end \ No newline at end of file diff --git a/lib/syntax/Expressions.ml b/lib/syntax/Expressions.ml index dcfade7..851e3c0 100644 --- a/lib/syntax/Expressions.ml +++ b/lib/syntax/Expressions.ml @@ -1,23 +1,59 @@ -open Literals -open UnaryOperators -open BinaryOperators +class virtual expression = + object + inherit Node.node + method virtual check_type : Environments.typeEnvironments -> Types.t + method virtual eval : Environments.evalEnvironment -> Literals.literal_value + end -type expressions = - | Literal of literals - | Identifier of string - | UnaryExpression of unary_operators * expressions - | BinaryExpression of binary_operators * expressions * expressions +class literal (lit : Literals.literal) = + object + inherit expression + method to_string = "Literal(" ^ lit#to_string ^ ")" + method check_type _ = lit#check_type + method eval _ = lit#value + end -let rec pp_expressions = function - | Literal l -> - let pp_l = pp_literals l in - Printf.sprintf "Literal(%s)" pp_l - | Identifier i -> Printf.sprintf "Identifier(\"%s\")" i - | 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 +class identifier (name : string) = + object + inherit expression + method to_string = "Identifier(" ^ name ^ ")" + + method check_type env = + try env#find name + with Not_found -> + raise (Failure ("Identifier '" ^ name ^ "' not found")) + + method eval env = env#find name + end + +class unaryOperation (operator : UnaryOperators.unaryOperator) + (operand : expression) = + object + inherit expression + + method to_string = + "UnaryOperation(" ^ operator#to_string ^ ", " ^ operand#to_string ^ ")" + + method check_type env = + let operand_type = operand#check_type env in + operator#check_type operand_type + + method eval env = operator#eval (operand#eval env) + end + +class binaryOperation (operator : BinaryOperators.binaryOperator) + (left : expression) (right : expression) = + object + inherit expression + + method to_string = + "BinaryOperation(" ^ operator#to_string ^ ", " ^ left#to_string ^ ", " + ^ right#to_string ^ ")" + + method check_type env = + let left_type = left#check_type env in + let right_type = right#check_type env in + operator#check_type (left_type, right_type) + + method eval env = operator#eval (left#eval env, right#eval env) + end \ No newline at end of file diff --git a/lib/syntax/Literals.ml b/lib/syntax/Literals.ml index f9f3bf3..3792ca1 100644 --- a/lib/syntax/Literals.ml +++ b/lib/syntax/Literals.ml @@ -1,15 +1,80 @@ -type literals = - | Integer of int - | Float of float - | Character of char - | String of string - | Boolean of bool - | Null +type literal_value = + [ `Int of int + | `Float of float + | `String of string + | `Bool of bool + | `Char of char + | `Null + | `Void ] -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 +let string_of_literal_value = function + | `Int i -> string_of_int i + | `Float f -> string_of_float f + | `String s -> "\"" ^ s ^ "\"" + | `Bool b -> string_of_bool b + | `Char c -> "'" ^ String.make 1 c ^ "'" + | `Null -> "null" + | `Void -> "void" + +class virtual literal = + object + inherit Node.node + method virtual value : literal_value + method virtual check_type : Types.t + end + +class eInteger (value : int) = + object + inherit literal + method value = `Int value + method to_string = "Integer(" ^ string_of_int value ^ ")" + method check_type = Types.IntegerType + end + +class eFloat (value : float) = + object + inherit literal + method value = `Float value + method to_string : string = "Float(" ^ string_of_float value ^ ")" + method check_type = Types.FloatType + end + +class eString (value : string) = + object + inherit literal + method value = `String value + method to_string = "String(\"" ^ value ^ "\")" + method check_type = Types.StringType + end + +class eBoolean (value : bool) = + object + inherit literal + method value = `Bool value + method to_string = "Boolean(" ^ string_of_bool value ^ ")" + method check_type = Types.BooleanType + end + +class eCharacter (value : char) = + object + inherit literal + method value = `Char value + method to_string = "Character(" ^ String.make 1 value ^ ")" + method check_type = Types.CharacterType + end + +class eNull = + object + inherit literal + method value = `Null + method to_string = "Null" + method check_type = Types.NullType + end + +class eVoid = + object + inherit literal + method value = `Void + method to_string = "Void" + method check_type = Types.VoidType + end \ No newline at end of file diff --git a/lib/syntax/Node.ml b/lib/syntax/Node.ml new file mode 100644 index 0000000..769c4b8 --- /dev/null +++ b/lib/syntax/Node.ml @@ -0,0 +1,6 @@ +class virtual node = + object + method virtual to_string : string + (* method virtual check_type : Types.type_ *) + (* method virtual eval *) + end \ No newline at end of file diff --git a/lib/syntax/Roots.ml b/lib/syntax/Roots.ml new file mode 100644 index 0000000..3205461 --- /dev/null +++ b/lib/syntax/Roots.ml @@ -0,0 +1,17 @@ +class program (statement : Statements.statement) = + object + inherit Node.node + method to_string = "Program(" ^ statement#to_string ^ ")" + + method check_type = + let env : Environments.typeEnvironments = + new Environments.typeEnvironments + in + statement#check_type env + + method eval = + let env : Environments.evalEnvironment = + new Environments.evalEnvironment + in + statement#eval env + end \ No newline at end of file diff --git a/lib/syntax/SourceFiles.ml b/lib/syntax/SourceFiles.ml deleted file mode 100644 index ea99f83..0000000 --- a/lib/syntax/SourceFiles.ml +++ /dev/null @@ -1,8 +0,0 @@ -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 index ef12427..fd25610 100644 --- a/lib/syntax/Statements.ml +++ b/lib/syntax/Statements.ml @@ -1,13 +1,52 @@ -open Expressions +class virtual statement = + object + inherit Node.node + method virtual check_type : Environments.typeEnvironments -> Types.t + method virtual eval : Environments.evalEnvironment -> Literals.literal_value + end -type statements = - | SequenceStatement of statements * statements - | ExpressionStatement of expressions +class sequence (left : statement) (right : statement) = + object + inherit statement -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 + method to_string = + "Sequence(" ^ left#to_string ^ ", " ^ right#to_string ^ ")" + + method check_type env = + let _ = left#check_type env in + right#check_type env + + method eval env = + let _ = left#eval env in + right#eval env + end + +class expression (expression : Expressions.expression) = + object + inherit statement + method to_string = "Expression(" ^ expression#to_string ^ ")" + method check_type env = expression#check_type env + method eval env = expression#eval env + end + +class variableDeclaration (name : string) (tp : Types.t) + (expression : Expressions.expression) = + object + inherit statement + + method to_string = + "VariableDeclaration(" ^ name ^ ", " ^ Types.string_of_t tp ^ ", " + ^ expression#to_string ^ ")" + + method check_type env = + let expression_type = expression#check_type env in + if tp = expression_type then ( + env#add name expression_type; + Types.VoidType) + else raise (Failure "VariableDeclaration: type mismatch") + + method eval env = + let value = expression#eval env in + env#add name value; + value + end \ No newline at end of file diff --git a/lib/syntax/Types.ml b/lib/syntax/Types.ml index 106c427..c267579 100644 --- a/lib/syntax/Types.ml +++ b/lib/syntax/Types.ml @@ -1,15 +1,17 @@ -type types = +type t = | IntegerType | FloatType - | CharacterType - | StringType | BooleanType + | StringType + | CharacterType + | NullType | VoidType -let pp_types = function +let string_of_t = function | IntegerType -> "IntegerType" | FloatType -> "FloatType" - | CharacterType -> "CharacterType" - | StringType -> "StringType" | BooleanType -> "BooleanType" - | VoidType -> "VoidType" + | StringType -> "StringType" + | CharacterType -> "CharacterType" + | NullType -> "NullType" + | VoidType -> "VoidType" \ No newline at end of file diff --git a/lib/syntax/UnaryOperators.ml b/lib/syntax/UnaryOperators.ml index bb6cd61..bf2a61d 100644 --- a/lib/syntax/UnaryOperators.ml +++ b/lib/syntax/UnaryOperators.ml @@ -1,5 +1,40 @@ -type unary_operators = ArithmeticNegation | LogicalNegation +class virtual unaryOperator = + object + inherit Node.node + method virtual check_type : Types.t -> Types.t + method virtual eval : Literals.literal_value -> Literals.literal_value + end -let pp_unary_operators = function - | ArithmeticNegation -> "ArithmeticNegation" - | LogicalNegation -> "LogicalNegation" +class arithmeticNegation = + object + inherit unaryOperator + method to_string = "ArithmeticNegation" + + method check_type (operand : Types.t) = + match operand with + | Types.IntegerType -> Types.IntegerType + | Types.FloatType -> Types.FloatType + | _ -> raise (Failure "ArithmeticNegation: operand must be a number") + + method eval operand = + match operand with + | `Int i -> `Int (-i) + | `Float f -> `Float (-.f) + | _ -> raise (Failure "ArithmeticNegation: operand must be a number") + end + +class logicalNegation = + object + inherit unaryOperator + method to_string = "LogicalNegation" + + method check_type (operand : Types.t) = + match operand with + | Types.BooleanType -> Types.BooleanType + | _ -> raise (Failure "LogicalNegation: operand must be a boolean") + + method eval operand = + match operand with + | `Bool b -> `Bool (not b) + | _ -> raise (Failure "LogicalNegation: operand must be a boolean") + end \ No newline at end of file diff --git a/lib/syntax/dune b/lib/syntax/dune index d14a6c1..825e84d 100644 --- a/lib/syntax/dune +++ b/lib/syntax/dune @@ -1,10 +1,14 @@ (library - (name Syntax) + (name syntax) (modules + Node Types - Literals + Environments BinaryOperators UnaryOperators + Literals Expressions Statements - SourceFiles)) + Roots) +; (libraries typing) +) diff --git a/test/ressources/test.🥐 b/test/ressources/test.🥐 deleted file mode 100644 index d9a2b18..0000000 --- a/test/ressources/test.🥐 +++ /dev/null @@ -1 +0,0 @@ -!vrai; \ No newline at end of file diff --git a/test/syntax/TestBinaryOperators.ml b/test/syntax/TestBinaryOperators.ml deleted file mode 100644 index a31fd1d..0000000 --- a/test/syntax/TestBinaryOperators.ml +++ /dev/null @@ -1,30 +0,0 @@ -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); - ("Should return \"Equals\"", "Equals", Equals); - ("Should return \"NotEquals\"", "NotEquals", NotEquals); - ("Should return \"LessThan\"", "LessThan", LessThan); - ("Should return \"LessThanEquals\"", "LessThanEquals", LessThanEquals); - ("Should return \"GreaterThan\"", "GreaterThan", GreaterThan); - ( "Should return \"GreaterThanEquals\"", - "GreaterThanEquals", - GreaterThanEquals ); - ("Should return \"And\"", "And", And); - ("Should return \"Or\"", "Or", Or); - ] - 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 deleted file mode 100644 index 2022928..0000000 --- a/test/syntax/TestExpressions.ml +++ /dev/null @@ -1,32 +0,0 @@ -open Alcotest -open Syntax - -let test_pp_expressions () = - let to_check = - [ - ( "Should return \"Literal(...)\"", - "Literal(Integer(1))", - Expressions.Literal (Literals.Integer 1) ); - ( "Should return \"Identifier(...)\"", - "Identifier(\"myVar\")", - Expressions.Identifier "myVar" ); - ( "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 deleted file mode 100644 index 75fd10a..0000000 --- a/test/syntax/TestLiterals.ml +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 4800822..0000000 --- a/test/syntax/TestSourceFiles.ml +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index b6e866e..0000000 --- a/test/syntax/TestStatements.ml +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 548204a..0000000 --- a/test/syntax/TestSyntax.ml +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 61ea3a9..0000000 --- a/test/syntax/TestTypes.ml +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 021cb1a..0000000 --- a/test/syntax/TestUnaryOperators.ml +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 0a0e0a0..0000000 --- a/test/syntax/dune +++ /dev/null @@ -1,4 +0,0 @@ -(test - (name TestSyntax) - (libraries Syntax alcotest) -) \ No newline at end of file diff --git a/test/test.🥐 b/test/test.🥐 new file mode 100644 index 0000000..bd60462 --- /dev/null +++ b/test/test.🥐 @@ -0,0 +1,5 @@ +var a : entier = 5; // 5 +var b : flottant = a + 3.8; // 8.8 +var c : flottant = b * a; // 44.0 + +var d : chaine = "Hello" + "World"; // "HelloWorld" \ No newline at end of file