feat: Support basic expression

This commit is contained in:
Lucàs
2024-07-02 15:33:58 +02:00
parent c91951308f
commit e563bce4f5
12 changed files with 231 additions and 25 deletions
+1
View File
@@ -5,6 +5,7 @@
# Build folder
_build/
*.opam
# Mac OS
.DS_Store
+2
View File
@@ -0,0 +1,2 @@
profile = default
version = 0.26.2
+4 -2
View File
@@ -1,4 +1,6 @@
;bin/dune
(executable
(public_name croissant)
(name main)
(libraries croissant))
(public_name croissant)
(libraries parser lexer ast))
+19 -1
View File
@@ -1 +1,19 @@
let () = print_endline "Hello, World!"
(* bin/main.ml *)
open Printf
open Ast
let () =
let lexbuf = Lexing.from_channel stdin in
let res =
try Parser.main Lexer.token lexbuf with
| Lexer.Error c ->
fprintf stderr "Lexical error at line %d: Unknown character '%c'\n"
lexbuf.lex_curr_p.pos_lnum c;
exit 1
| Parser.Error ->
fprintf stderr "Parse error at line %d:\n" lexbuf.lex_curr_p.pos_lnum;
exit 1
in
let _ = res in
Printf.printf "%s\n" (string_of_source_file res)
+10 -16
View File
@@ -1,26 +1,20 @@
(lang dune 3.10)
(lang dune 3.4)
(name croissant)
(generate_opam_files true)
(source
(github username/reponame))
(authors "Author Name")
(maintainers "Maintainer Name")
(source (github LucasVbr/croissant))
(authors "LucasVbr")
(maintainers "LucasVbr")
(license LICENSE)
(documentation https://url/to/documentation)
;(documentation https://url/to/documentation)
(package
(name croissant)
(synopsis "A short synopsis")
(description "A longer description")
(depends ocaml dune)
(depends ocaml dune alcotest menhir ocamlformat)
(tags
(topics "to describe" your project)))
; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
("Custom programming language" "French")
)
)
(using menhir 2.1)
+34
View File
@@ -0,0 +1,34 @@
(* lib/ast.ml *)
type binary_operator = Add | Substract | Multiply | Divide
type expression =
| IntegerLiteral of int
| BinaryExpression of binary_operator * expression * expression
type statement = ExpressionStatement of expression
type source_file = SourceFile of statement list
(* Print AST *)
let string_of_binary_operator = function
| Add -> "Add"
| Substract -> "Substract"
| Multiply -> "Multiply"
| Divide -> "Divide"
let rec string_of_expression = function
| IntegerLiteral i -> "IntegerLiteral(" ^ string_of_int i ^ ")"
| BinaryExpression (op, e1, e2) ->
"BinaryExpression("
^ string_of_binary_operator op
^ ", " ^ string_of_expression e1 ^ ", " ^ string_of_expression e2 ^ ")"
let string_of_statement = function
| ExpressionStatement e ->
"ExpressionStatement(" ^ string_of_expression e ^ ")"
let string_of_source_file = function
| SourceFile stmts ->
let stmt_strings = List.map string_of_statement stmts in
"SourceFile([" ^ String.concat ", " stmt_strings ^ "])"
+20 -1
View File
@@ -1,2 +1,21 @@
;lib/dune
(library
(name croissant))
(name lexer)
(modules lexer)
(libraries parser))
(library
(name parser)
(modules parser)
(libraries ast))
(library
(name ast)
(modules ast))
(menhir
(modules parser))
(ocamllex
(modules lexer))
+28
View File
@@ -0,0 +1,28 @@
(* lib/lexer.mll *)
{
open Parser
exception Error of char
}
let line_comment = "//" [^ '\n']*
let digit = ['0'-'9']
let integer = digit+
rule token = parse
| [' ' '\t'] | line_comment { token lexbuf }
| ['\n'] { Lexing.new_line lexbuf; token lexbuf }
| '+' { PLUS }
| '-' { MINUS }
| '*' { TIMES }
| '/' { DIVIDE }
| ';' { SEMICOLON }
| integer as lxm { INT(int_of_string lxm) }
| '(' { LPAREN }
| ')' { RPAREN }
| eof { EOF }
| _ as c { raise (Error c) }
+51
View File
@@ -0,0 +1,51 @@
/* lib/parser.mly */
%{
open Ast
%}
%token <int> INT
%token PLUS "+"
%token MINUS "-"
%token TIMES "*"
%token DIVIDE "/"
%token LPAREN "("
%token RPAREN ")"
%token SEMICOLON ";"
%token EOF
%left "+" "-"
%left "*" "/"
//%nonassoc UMINUS
%start main
%type <source_file> main
%%
main:
| statements EOF { SourceFile($1) }
statements:
| statement ";" { [$1] }
| statement ";" statements { $1 :: $3 }
statement:
| expression { ExpressionStatement($1) }
expression:
| literal { $1 }
| binary_expression { $1 }
| "(" expression ")" { $2 }
literal:
| INT { IntegerLiteral($1) }
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) }
+54
View File
@@ -0,0 +1,54 @@
(* test/ast.ml *)
open Alcotest
open Ast
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)
let test_string_of_expression () =
let expr = BinaryExpression (Add, IntegerLiteral 1, IntegerLiteral 2) in
check string "1 + 2"
"BinaryExpression(Add, IntegerLiteral(1), IntegerLiteral(2))"
(string_of_expression expr)
let test_string_of_statement () =
let stmt = ExpressionStatement (IntegerLiteral 42) in
check string "42;" "ExpressionStatement(IntegerLiteral(42))"
(string_of_statement stmt)
let test_string_of_source_file () =
let source_file =
SourceFile
[
ExpressionStatement (IntegerLiteral 1);
ExpressionStatement
(BinaryExpression (Add, IntegerLiteral 2, IntegerLiteral 3));
]
in
check string "1; 2 + 3;"
"SourceFile([ExpressionStatement(IntegerLiteral(1)), \
ExpressionStatement(BinaryExpression(Add, IntegerLiteral(2), \
IntegerLiteral(3)))])"
(string_of_source_file source_file)
let () =
let open Alcotest in
run "AST tests"
[
( "string_of_binary_operator",
[
test_case "string_of_binary_operator" `Quick
test_string_of_binary_operator;
] );
( "string_of_expression",
[ test_case "string_of_expression" `Quick test_string_of_expression ] );
( "string_of_statement",
[ test_case "string_of_statement" `Quick test_string_of_statement ] );
( "string_of_source_file",
[ test_case "string_of_source_file" `Quick test_string_of_source_file ]
);
]
View File
+4 -1
View File
@@ -1,2 +1,5 @@
;test/dune
(test
(name croissant))
(name ast)
(libraries ast alcotest))