diff --git a/README.md b/README.md index 6bc30a6..665efaf 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,8 @@ User { ### Control Flow -Control flow in One is still quite limited, as the `for` keyword has not been implemented yet. `if`, `else` and `elif` statements are fully implemented and are written like this. +Control flow in One isn't fully implemented yet, but it is already functional. +`if`, `else` and `elif` statements are fully implemented and are written like this: ``` let x int = 17; @@ -225,7 +226,15 @@ if x >= 100 { } ``` -Using parentheses around the condition isn't necessary. +`while` loops are very similar, and can be written like this: + +``` +let i int = 0; +while i < 10 { + print(i); + i++; +} +``` ### The main function diff --git a/generator.v b/generator.v index 693a630..0c9fc67 100644 --- a/generator.v +++ b/generator.v @@ -1,3 +1,4 @@ + module main import strings @@ -158,6 +159,12 @@ fn (mut g Generator) gen_stmt(stmt Stmt) { g.out.write_string(') ') g.gen_stmt(stmt.block) } + WhileLoop { + g.out.write_string('while (') + g.gen_expr(stmt.guard) + g.out.write_string(') ') + g.gen_stmt(stmt.block) + } } } diff --git a/lexer.v b/lexer.v index a5f3932..c08dccb 100644 --- a/lexer.v +++ b/lexer.v @@ -10,7 +10,7 @@ enum TokenType as u8 { kw_if kw_else kw_elif - kw_for + kw_while kw_break kw_fn kw_return @@ -106,7 +106,7 @@ fn toktype_from_kw(kw string) TokenType { 'if' {.kw_if} 'else' {.kw_else} 'elif' {.kw_elif} - 'for' {.kw_for} + 'while' {.kw_while} 'break' {.kw_break} 'fn' {.kw_fn} 'return' {.kw_return} @@ -133,7 +133,7 @@ fn is_real(str string) bool { fn is_keyword(str string) bool { return [ - "void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable" + "void", "int", "real", "bool", "string", "if", "else", "elif", "while", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable" ].contains(str) } diff --git a/one b/one index 6074933..e7a997e 100755 Binary files a/one and b/one differ diff --git a/parser.v b/parser.v index 2a86262..586b4ee 100644 --- a/parser.v +++ b/parser.v @@ -122,7 +122,9 @@ fn (mut s SymbolTable) is_in_global_scope() bool { // ------------------------------------------- Expressions -type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | StringLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember | ClassInstantiation | MemberAccess +type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | StringLiteral | + Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember | + ClassInstantiation | MemberAccess struct VoidExpr {} @@ -204,7 +206,8 @@ struct FnCall { // ------------------------------------------- Statements -type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | IfStmt | ElseStmt | ElifStmt | FuncDecl | Param | ClassDecl +type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | IfStmt | ElseStmt | ElifStmt | FuncDecl | Param | + ClassDecl | WhileLoop struct VarDecl { name string @@ -251,6 +254,11 @@ struct ElifStmt { block Block } +struct WhileLoop { + guard Expr + block Block +} + struct Param { name string type string @@ -529,6 +537,10 @@ fn (mut p Parser) get_expr_is_immutable(expr Expr) bool { memberinfo := classinfo.members_info[expr.member] or {parse_error("Undefined member ${expr.member}")} memberinfo.is_immutable } + Variable { + varinfo := p.symbols.lookup_var(expr.name) or {parse_error("Undefined variable ${expr.name}")} + varinfo.is_immutable + } else {true} } } @@ -616,6 +628,7 @@ fn (mut p Parser) parse_statement() Stmt { .kw_if {return p.parse_if()} .kw_else {return p.parse_else()} .kw_elif {return p.parse_elif()} + .kw_while {return p.parse_while()} else {return p.parse_expr_stmt()} } } @@ -768,6 +781,17 @@ fn (mut p Parser) parse_return_stmt() ReturnStmt { } } +fn (mut p Parser) parse_while() WhileLoop { + p.expect(.kw_while) + cond := p.parse_expr(.base) + if p.get_expr_type(cond) != 'bool' { + parse_error('While loop guard must be of type bool') + } + block := p.parse_block(false) + + return WhileLoop {cond, block} +} + fn (mut p Parser) parse_if() IfStmt { p.expect(.kw_if) cond := p.parse_expr(.base)