Compare commits
2 Commits
c0bbb82e71
...
90ab17da24
| Author | SHA1 | Date | |
|---|---|---|---|
| 90ab17da24 | |||
| 99d63ff769 |
35
README.md
35
README.md
@@ -86,6 +86,21 @@ get translated to during compilation. Comparisons and operations on strings are
|
|||||||
and quite buggy, but you are free to use string literals for prints or simple variable declarations with no issues.
|
and quite buggy, but you are free to use string literals for prints or simple variable declarations with no issues.
|
||||||
Variables cannot be declared with type `void`.
|
Variables cannot be declared with type `void`.
|
||||||
|
|
||||||
|
The `string` type actually behaves similarly to how a class would. While using the variable directly
|
||||||
|
gives you access to the actual string (which in C corresponds to the `char*`), you can use `.len` to
|
||||||
|
get the length of the string. Note that `len` is an immutable member, so you cannot maually set it.
|
||||||
|
|
||||||
|
```
|
||||||
|
let mystring string = "this is my string";
|
||||||
|
print(mystring, mystring.len)
|
||||||
|
```
|
||||||
|
|
||||||
|
produces this output:
|
||||||
|
|
||||||
|
```
|
||||||
|
this is my string 17
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
@@ -133,6 +148,26 @@ let myuser User = User{17, "uan", false}
|
|||||||
Class types can be used anywhere primitive types can, such as function arguments
|
Class types can be used anywhere primitive types can, such as function arguments
|
||||||
or other classes' members.
|
or other classes' members.
|
||||||
|
|
||||||
|
Class members can be defined as immutable with the `immutable` keyword before the member name.
|
||||||
|
This is checked at compile time and prevents that member's value to be changed after instantiation.
|
||||||
|
For example, this code would trigger a parse error, `as u.id = 0` attempts to change an immutable
|
||||||
|
member's value.
|
||||||
|
|
||||||
|
```
|
||||||
|
class User {
|
||||||
|
age int
|
||||||
|
name string
|
||||||
|
mail_verified bool
|
||||||
|
immutable id int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_values(u User) {
|
||||||
|
u.age = 10;
|
||||||
|
u.name = "new name";
|
||||||
|
u.id = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Print
|
### Print
|
||||||
|
|||||||
31
generator.v
31
generator.v
@@ -24,6 +24,7 @@ fn mangle_struct(name string) string {
|
|||||||
|
|
||||||
|
|
||||||
fn get_type_format(type string) string {
|
fn get_type_format(type string) string {
|
||||||
|
dump(type)
|
||||||
return match type {
|
return match type {
|
||||||
'int', 'bool' {'d'}
|
'int', 'bool' {'d'}
|
||||||
'real' {'f'}
|
'real' {'f'}
|
||||||
@@ -46,7 +47,7 @@ fn (mut g Generator) get_c_type(typ string) string {
|
|||||||
return match typ {
|
return match typ {
|
||||||
'real' {'float'}
|
'real' {'float'}
|
||||||
'int' {'int32_t'}
|
'int' {'int32_t'}
|
||||||
'string' {'char*'}
|
'string' {'OneString'}
|
||||||
else {typ}
|
else {typ}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,12 +71,16 @@ fn (mut g Generator) gen_class_print_func(stmt ClassDecl) {
|
|||||||
g.out.writeln('for(int i=0; i<indent + 1; i++) printf(" ");')
|
g.out.writeln('for(int i=0; i<indent + 1; i++) printf(" ");')
|
||||||
g.out.write_string('printf("${member.name}: ");')
|
g.out.write_string('printf("${member.name}: ");')
|
||||||
|
|
||||||
if g.symbols.lookup_class(member.type) != none {
|
if member.type != 'string' && g.symbols.lookup_class(member.type) != none {
|
||||||
inner_struct_name := mangle_struct(member.type)
|
inner_struct_name := mangle_struct(member.type)
|
||||||
g.out.writeln('print_${inner_struct_name}(s.${member.name}, indent + 1);')
|
g.out.writeln('print_${inner_struct_name}(s.${member.name}, indent + 1);')
|
||||||
} else {
|
} else {
|
||||||
format := get_type_format(member.type)
|
format := get_type_format(member.type)
|
||||||
g.out.writeln('printf("%${format}\\n", s.${member.name});')
|
g.out.write_string('printf("%${format}\\n", s.${member.name}')
|
||||||
|
if member.type == 'string' {
|
||||||
|
g.out.write_string('.string')
|
||||||
|
}
|
||||||
|
g.out.writeln(');')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,13 +173,21 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
g.out.write_string(expr.val.str())
|
g.out.write_string(expr.val.str())
|
||||||
}
|
}
|
||||||
StringLiteral {
|
StringLiteral {
|
||||||
g.out.write_string('\"${expr.val}\"')
|
g.out.write_string('(OneString){\"${expr.val}\", ${expr.val.len}}')
|
||||||
}
|
}
|
||||||
Variable {
|
Variable {
|
||||||
g.out.write_string(mangle_var(expr.name))
|
g.out.write_string(mangle_var(expr.name))
|
||||||
}
|
}
|
||||||
UnaryExpr {
|
UnaryExpr {
|
||||||
g.out.write_string('(${mangle_var(expr.ident)}${expr.op})')
|
if expr.op_on_left {
|
||||||
|
g.out.write_string('(${expr.op}')
|
||||||
|
g.gen_expr(expr.expr)
|
||||||
|
g.out.write_string(')')
|
||||||
|
} else {
|
||||||
|
g.out.write_string('(')
|
||||||
|
g.gen_expr(expr.expr)
|
||||||
|
g.out.write_string('${expr.op})')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BinaryExpr {
|
BinaryExpr {
|
||||||
g.out.write_string('(')
|
g.out.write_string('(')
|
||||||
@@ -188,16 +201,20 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
for i < expr.exprs.len {
|
for i < expr.exprs.len {
|
||||||
inner_expr := expr.exprs[i];
|
inner_expr := expr.exprs[i];
|
||||||
expr_type := expr.types[i];
|
expr_type := expr.types[i];
|
||||||
if g.symbols.lookup_class(expr_type) != none {
|
if expr_type != 'string' && g.symbols.lookup_class(expr_type) != none {
|
||||||
class_name := mangle_struct(expr_type)
|
class_name := mangle_struct(expr_type)
|
||||||
g.out.write_string('print_${class_name}(')
|
g.out.write_string('print_${class_name}(')
|
||||||
g.gen_expr(inner_expr)
|
g.gen_expr(inner_expr)
|
||||||
g.out.write_string(', 0);')
|
g.out.write_string(', 0);')
|
||||||
|
} else {
|
||||||
g.out.write_string('printf(\"')
|
g.out.write_string('printf(\"')
|
||||||
format := get_type_format(expr_type)
|
format := get_type_format(expr_type)
|
||||||
g.out.write_string('%${format}')
|
g.out.write_string('%${format}')
|
||||||
g.out.write_string('\", ')
|
g.out.write_string('\", ')
|
||||||
g.gen_expr(inner_expr)
|
g.gen_expr(inner_expr)
|
||||||
|
if expr_type == 'string' {
|
||||||
|
g.out.write_string('.string')
|
||||||
|
}
|
||||||
g.out.write_string(');')
|
g.out.write_string(');')
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -254,7 +271,7 @@ fn (mut g Generator) gen_c(program []Stmt) string {
|
|||||||
g.out.writeln('#include <stdio.h>')
|
g.out.writeln('#include <stdio.h>')
|
||||||
g.out.writeln('#include <stdbool.h>')
|
g.out.writeln('#include <stdbool.h>')
|
||||||
g.out.writeln('#include <stdint.h>')
|
g.out.writeln('#include <stdint.h>')
|
||||||
//g.out.writeln('typedef struct __one_string_builtin__ {\nchar* string;\nint len;\n} string;')
|
g.out.writeln('typedef struct {\nchar* string;\nint len;\n} OneString;')
|
||||||
for stmt in program {
|
for stmt in program {
|
||||||
g.gen_stmt(stmt)
|
g.gen_stmt(stmt)
|
||||||
}
|
}
|
||||||
|
|||||||
4
lexer.v
4
lexer.v
@@ -5,6 +5,7 @@ import term
|
|||||||
enum TokenType as u8 {
|
enum TokenType as u8 {
|
||||||
kw_let
|
kw_let
|
||||||
kw_const
|
kw_const
|
||||||
|
kw_immutable
|
||||||
type
|
type
|
||||||
kw_if
|
kw_if
|
||||||
kw_else
|
kw_else
|
||||||
@@ -108,6 +109,7 @@ fn toktype_from_kw(kw string) TokenType {
|
|||||||
'true', 'false' {.boolean}
|
'true', 'false' {.boolean}
|
||||||
'print' {.kw_print}
|
'print' {.kw_print}
|
||||||
'class' {.kw_class}
|
'class' {.kw_class}
|
||||||
|
'immutable' {.kw_immutable}
|
||||||
else {.unknown}
|
else {.unknown}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ fn is_real(str string) bool {
|
|||||||
|
|
||||||
fn is_keyword(str string) bool {
|
fn is_keyword(str string) bool {
|
||||||
return [
|
return [
|
||||||
"void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class"
|
"void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable"
|
||||||
].contains(str)
|
].contains(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
133
parser.v
133
parser.v
@@ -5,12 +5,13 @@ import term
|
|||||||
// ------------------------------------------- Precedence
|
// ------------------------------------------- Precedence
|
||||||
|
|
||||||
enum Precedence {
|
enum Precedence {
|
||||||
lowest
|
base
|
||||||
assignment // = , +=, -=
|
assignment // = , +=, -=
|
||||||
comparison // ==, !=, <, >
|
comparison // ==, !=, <, >
|
||||||
sum // +, -
|
sum // +, -
|
||||||
product // *, /
|
product // *, /
|
||||||
prefix // -x, !x
|
prefix // -x, !x
|
||||||
|
suffix // ++, --
|
||||||
call // function()
|
call // function()
|
||||||
access // .
|
access // .
|
||||||
}
|
}
|
||||||
@@ -22,7 +23,8 @@ fn (p Parser) get_precedence(tok_type TokenType) Precedence {
|
|||||||
.plus, .minus { .sum }
|
.plus, .minus { .sum }
|
||||||
.star, .slash { .product }
|
.star, .slash { .product }
|
||||||
.dot { .access }
|
.dot { .access }
|
||||||
else { .lowest }
|
.increment, .decrement { .suffix }
|
||||||
|
else { .base}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +34,7 @@ type SymbolInfo = VarSymbolInfo | FuncSymbolInfo | ClassSymbolInfo
|
|||||||
|
|
||||||
struct VarSymbolInfo {
|
struct VarSymbolInfo {
|
||||||
type string
|
type string
|
||||||
|
is_immutable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FuncSymbolInfo {
|
struct FuncSymbolInfo {
|
||||||
@@ -51,7 +54,7 @@ mut:
|
|||||||
structs map[string]ClassSymbolInfo
|
structs map[string]ClassSymbolInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s SymbolTable) define_var(name string, typ string) {
|
fn (mut s SymbolTable) define_var(name string, typ string, is_const bool) {
|
||||||
$if debug {
|
$if debug {
|
||||||
dump(s.variable_scopes.len)
|
dump(s.variable_scopes.len)
|
||||||
}
|
}
|
||||||
@@ -66,6 +69,7 @@ fn (mut s SymbolTable) define_var(name string, typ string) {
|
|||||||
|
|
||||||
s.variable_scopes[s.variable_scopes.len-1][name] = VarSymbolInfo{
|
s.variable_scopes[s.variable_scopes.len-1][name] = VarSymbolInfo{
|
||||||
type: typ
|
type: typ
|
||||||
|
is_immutable: is_const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +100,10 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo {
|
|||||||
fn (mut s SymbolTable) define_class(name string, members []ClassMember) {
|
fn (mut s SymbolTable) define_class(name string, members []ClassMember) {
|
||||||
mut members_info := map[string]VarSymbolInfo{}
|
mut members_info := map[string]VarSymbolInfo{}
|
||||||
for member in members {
|
for member in members {
|
||||||
members_info[member.name] = VarSymbolInfo{member.type}
|
members_info[member.name] = VarSymbolInfo{
|
||||||
|
type: member.type,
|
||||||
|
is_immutable: member.is_immutable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info}
|
s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info}
|
||||||
}
|
}
|
||||||
@@ -120,8 +127,9 @@ type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | B
|
|||||||
struct VoidExpr {}
|
struct VoidExpr {}
|
||||||
|
|
||||||
struct UnaryExpr {
|
struct UnaryExpr {
|
||||||
ident string
|
expr Expr
|
||||||
op string
|
op string
|
||||||
|
op_on_left bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BinaryExpr {
|
struct BinaryExpr {
|
||||||
@@ -157,11 +165,13 @@ struct TypeExpr {
|
|||||||
struct ClassMember {
|
struct ClassMember {
|
||||||
name string
|
name string
|
||||||
type string
|
type string
|
||||||
|
is_immutable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MemberAccess {
|
struct MemberAccess {
|
||||||
from Expr
|
from Expr
|
||||||
member string
|
member string
|
||||||
|
member_type string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClassInstantiation {
|
struct ClassInstantiation {
|
||||||
@@ -275,7 +285,6 @@ fn (mut p Parser) expect(type TokenType) {
|
|||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn (mut p Parser) expect_ident_is_class(ident string) {
|
fn (mut p Parser) expect_ident_is_class(ident string) {
|
||||||
if !p.is_ident_class(ident) {panic("Expected type or class type but got identifier")}
|
if !p.is_ident_class(ident) {panic("Expected type or class type but got identifier")}
|
||||||
}
|
}
|
||||||
@@ -319,6 +328,7 @@ fn (mut p Parser) parse_primary() Expr {
|
|||||||
.type {p.parse_type(token.text)}
|
.type {p.parse_type(token.text)}
|
||||||
.lparen {p.parse_paren()}
|
.lparen {p.parse_paren()}
|
||||||
.kw_print {p.parse_print()}
|
.kw_print {p.parse_print()}
|
||||||
|
.plus, .minus {p.parse_unary_left(token.text)}
|
||||||
else {parse_error("Unexpected Token")}
|
else {parse_error("Unexpected Token")}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,15 +336,13 @@ fn (mut p Parser) parse_primary() Expr {
|
|||||||
fn (mut p Parser) parse_expr(prec Precedence) Expr {
|
fn (mut p Parser) parse_expr(prec Precedence) Expr {
|
||||||
mut expr := p.parse_primary()
|
mut expr := p.parse_primary()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for int(prec) < int(p.get_precedence(p.peek().type)) {
|
for int(prec) < int(p.get_precedence(p.peek().type)) {
|
||||||
op_tok := p.next()
|
op_tok := p.next()
|
||||||
|
|
||||||
if op_tok.type == .dot {
|
expr = match op_tok.type {
|
||||||
expr = p.parse_member_access(expr)
|
.dot {p.parse_member_access(expr)}
|
||||||
} else {
|
.increment, .decrement {p.parse_unary_right(expr, op_tok.text)}
|
||||||
expr = p.parse_binary(expr, op_tok.text, p.get_precedence(op_tok.type))
|
else {p.parse_binary(expr, op_tok.text, p.get_precedence(op_tok.type))}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,12 +357,7 @@ fn (mut p Parser) parse_ident(ident string) Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.inside_struct {
|
|
||||||
return p.parse_class_member(ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
return match p.peek().type {
|
return match p.peek().type {
|
||||||
.increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}}
|
|
||||||
.lparen {p.parse_call(ident)}
|
.lparen {p.parse_call(ident)}
|
||||||
else {Variable{ident}}
|
else {Variable{ident}}
|
||||||
}
|
}
|
||||||
@@ -363,10 +366,19 @@ fn (mut p Parser) parse_ident(ident string) Expr {
|
|||||||
fn (mut p Parser) parse_member_access(from Expr) MemberAccess {
|
fn (mut p Parser) parse_member_access(from Expr) MemberAccess {
|
||||||
member_tok := p.next()
|
member_tok := p.next()
|
||||||
if member_tok.type != .identifier {parse_error("Expected identifier after member access")}
|
if member_tok.type != .identifier {parse_error("Expected identifier after member access")}
|
||||||
return MemberAccess {from: from, member: member_tok.text}
|
from_class := p.symbols.lookup_class(p.get_expr_type(from)) or {panic("Accessing member from non-class type")}
|
||||||
|
if !(member_tok.text in from_class.members_info) {panic("Accessing undefined member ${member_tok.text}")}
|
||||||
|
member_type := from_class.members_info[member_tok.text].type
|
||||||
|
return MemberAccess {from: from, member: member_tok.text, member_type: member_type}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_class_member(name string) ClassMember {
|
fn (mut p Parser) parse_class_member() ClassMember {
|
||||||
|
mut is_immut := false
|
||||||
|
if p.peek().type == .kw_immutable {
|
||||||
|
is_immut = true
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
member_name := p.peek().text
|
||||||
p.expect(.identifier)
|
p.expect(.identifier)
|
||||||
|
|
||||||
type_tok := p.peek()
|
type_tok := p.peek()
|
||||||
@@ -376,12 +388,12 @@ fn (mut p Parser) parse_class_member(name string) ClassMember {
|
|||||||
p.expect_ident_is_class(type_tok.text)
|
p.expect_ident_is_class(type_tok.text)
|
||||||
type_tok.text
|
type_tok.text
|
||||||
}
|
}
|
||||||
else{parse_error("Expected type after class member ${name} in declaration, got ${p.peek().type}")}
|
else{parse_error("Expected type after class member ${member_name} in declaration, got ${p.peek().type}")}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.next()
|
p.next()
|
||||||
p.expect(.semicolon)
|
p.expect(.semicolon)
|
||||||
return ClassMember{name: name, type: type_name}
|
return ClassMember{name: member_name, type: type_name is_immutable: is_immut}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_class_inst(name string) ClassInstantiation {
|
fn (mut p Parser) parse_class_inst(name string) ClassInstantiation {
|
||||||
@@ -390,7 +402,7 @@ fn (mut p Parser) parse_class_inst(name string) ClassInstantiation {
|
|||||||
|
|
||||||
if p.peek().type != .rbracket {
|
if p.peek().type != .rbracket {
|
||||||
for {
|
for {
|
||||||
member_values << p.parse_expr(.lowest)
|
member_values << p.parse_expr(.base)
|
||||||
if p.peek().type == .comma {
|
if p.peek().type == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} else {
|
||||||
@@ -408,7 +420,7 @@ fn (mut p Parser) parse_call(name string) FnCall {
|
|||||||
|
|
||||||
if p.peek().type != .rparen {
|
if p.peek().type != .rparen {
|
||||||
for {
|
for {
|
||||||
args << p.parse_expr(.lowest)
|
args << p.parse_expr(.base)
|
||||||
if p.peek().type == .comma {
|
if p.peek().type == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} else {
|
||||||
@@ -425,7 +437,7 @@ fn (mut p Parser) parse_print() PrintExpr {
|
|||||||
mut exprs := []Expr{}
|
mut exprs := []Expr{}
|
||||||
mut types := []string{}
|
mut types := []string{}
|
||||||
for p.peek().type != .rparen {
|
for p.peek().type != .rparen {
|
||||||
expr := p.parse_expr(.lowest)
|
expr := p.parse_expr(.base)
|
||||||
exprs << expr
|
exprs << expr
|
||||||
types << p.get_expr_type(expr)
|
types << p.get_expr_type(expr)
|
||||||
if p.peek().type == .comma {
|
if p.peek().type == .comma {
|
||||||
@@ -438,7 +450,29 @@ fn (mut p Parser) parse_print() PrintExpr {
|
|||||||
return PrintExpr{exprs: exprs, types: types}
|
return PrintExpr{exprs: exprs, types: types}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) parse_unary_right(expr Expr, op string) UnaryExpr {
|
||||||
|
if p.get_expr_is_immutable(expr) {
|
||||||
|
parse_error("Cannot perform operation ${op} on immutable expression ${expr}")
|
||||||
|
}
|
||||||
|
if !p.is_op_valid_for_type(p.get_expr_type(expr), op) {
|
||||||
|
parse_error("Invalid operation ${op} for type ${p.get_expr_type(expr)}")
|
||||||
|
}
|
||||||
|
return UnaryExpr {expr: expr, op: op, op_on_left: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) parse_unary_left(op string) UnaryExpr {
|
||||||
|
expr := p.parse_expr(.prefix)
|
||||||
|
return UnaryExpr{expr: expr, op: op, op_on_left: true}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr {
|
fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr {
|
||||||
|
|
||||||
|
if op in ['=', '+=', '-=', '*=', '/='] {
|
||||||
|
if p.get_expr_is_immutable(left) {
|
||||||
|
parse_error("Cannot assign to immutable expression ${left}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
right := p.parse_expr(prec)
|
right := p.parse_expr(prec)
|
||||||
binary_expr := BinaryExpr{left, op, right}
|
binary_expr := BinaryExpr{left, op, right}
|
||||||
|
|
||||||
@@ -453,7 +487,7 @@ fn (mut p Parser) parse_type(type string) Expr {
|
|||||||
|
|
||||||
if p.peek().type == .lparen {
|
if p.peek().type == .lparen {
|
||||||
p.next()
|
p.next()
|
||||||
expr := p.parse_expr(.lowest)
|
expr := p.parse_expr(.base)
|
||||||
p.expect(.rparen)
|
p.expect(.rparen)
|
||||||
|
|
||||||
return TypeCast {
|
return TypeCast {
|
||||||
@@ -466,7 +500,7 @@ fn (mut p Parser) parse_type(type string) Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_paren() ParenExpr {
|
fn (mut p Parser) parse_paren() ParenExpr {
|
||||||
expr := p.parse_expr(.lowest)
|
expr := p.parse_expr(.base)
|
||||||
p.expect(.rparen)
|
p.expect(.rparen)
|
||||||
return ParenExpr{expr: expr}
|
return ParenExpr{expr: expr}
|
||||||
}
|
}
|
||||||
@@ -483,6 +517,20 @@ fn (mut p Parser) is_ident_class(ident string) bool {
|
|||||||
return p.symbols.lookup_class(ident) != none
|
return p.symbols.lookup_class(ident) != none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) get_expr_is_immutable(expr Expr) bool {
|
||||||
|
return match expr {
|
||||||
|
ParenExpr {p.get_expr_is_immutable(expr.expr)}
|
||||||
|
UnaryExpr {p.get_expr_is_immutable(expr.expr)}
|
||||||
|
TypeCast {p.get_expr_is_immutable(expr.expr)}
|
||||||
|
MemberAccess {
|
||||||
|
classinfo := p.symbols.lookup_class(p.get_expr_type(expr.from)) or {parse_error("Invalid class")}
|
||||||
|
memberinfo := classinfo.members_info[expr.member] or {parse_error("Undefined member ${expr.member}")}
|
||||||
|
memberinfo.is_immutable
|
||||||
|
}
|
||||||
|
else {true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut p Parser) get_expr_type(expr Expr) string {
|
fn (mut p Parser) get_expr_type(expr Expr) string {
|
||||||
return match expr {
|
return match expr {
|
||||||
ParenExpr {p.get_expr_type(expr.expr)}
|
ParenExpr {p.get_expr_type(expr.expr)}
|
||||||
@@ -492,6 +540,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
|
|||||||
StringLiteral {'string'}
|
StringLiteral {'string'}
|
||||||
VoidExpr {'void'}
|
VoidExpr {'void'}
|
||||||
TypeExpr {expr.name}
|
TypeExpr {expr.name}
|
||||||
|
UnaryExpr {p.get_expr_type(expr.expr)}
|
||||||
BinaryExpr {
|
BinaryExpr {
|
||||||
p.check_binary_expr_types(expr)
|
p.check_binary_expr_types(expr)
|
||||||
left_t := p.get_expr_type(expr.left)
|
left_t := p.get_expr_type(expr.left)
|
||||||
@@ -513,13 +562,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
|
|||||||
fninfo.type
|
fninfo.type
|
||||||
}
|
}
|
||||||
MemberAccess {
|
MemberAccess {
|
||||||
mut type_from := p.get_expr_type(expr.from)
|
expr.member_type
|
||||||
classinfo := p.symbols.lookup_class(type_from)or{parse_error("Non-existant class ${type_from}")}
|
|
||||||
if expr.member in classinfo.members_info {
|
|
||||||
classinfo.members_info[expr.member].type
|
|
||||||
} else {
|
|
||||||
parse_error("Undefined class member ${expr.member}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ClassInstantiation {expr.name}
|
ClassInstantiation {expr.name}
|
||||||
else {"Tried getting type of unexpected Expr"}
|
else {"Tried getting type of unexpected Expr"}
|
||||||
@@ -529,7 +572,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
|
|||||||
fn (mut p Parser) is_op_valid_for_type(type string, op string) bool {
|
fn (mut p Parser) is_op_valid_for_type(type string, op string) bool {
|
||||||
global := ['=', '==', '!=']
|
global := ['=', '==', '!=']
|
||||||
mut legal_ops := match type {
|
mut legal_ops := match type {
|
||||||
'int', 'real' {['+', '-', '*', '/', '<', '>', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=']}
|
'int', 'real' {['+', '-', '*', '/', '<', '>', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '++', '--']}
|
||||||
'bool' {['=']}
|
'bool' {['=']}
|
||||||
else {[]}
|
else {[]}
|
||||||
}
|
}
|
||||||
@@ -586,7 +629,7 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.expect(.equals)
|
p.expect(.equals)
|
||||||
val := p.parse_expr(.lowest)
|
val := p.parse_expr(.base)
|
||||||
|
|
||||||
if type_tok.text == 'void' {
|
if type_tok.text == 'void' {
|
||||||
parse_error("Cannot declare a variable of type void")
|
parse_error("Cannot declare a variable of type void")
|
||||||
@@ -596,7 +639,7 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
|
|||||||
}
|
}
|
||||||
p.expect(.semicolon)
|
p.expect(.semicolon)
|
||||||
|
|
||||||
p.symbols.define_var(name_tok.text, type_tok.text)
|
p.symbols.define_var(name_tok.text, type_tok.text, is_const)
|
||||||
|
|
||||||
return VarDecl {
|
return VarDecl {
|
||||||
name: name_tok.text
|
name: name_tok.text
|
||||||
@@ -640,7 +683,7 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
|||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
params << Param{p_name, p_type}
|
params << Param{p_name, p_type}
|
||||||
p.symbols.define_var(p_name, p_type)
|
p.symbols.define_var(p_name, p_type, false)
|
||||||
|
|
||||||
if p.peek().type == .comma {
|
if p.peek().type == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
@@ -695,8 +738,8 @@ fn (mut p Parser) parse_class() ClassDecl {
|
|||||||
p.expect(.identifier)
|
p.expect(.identifier)
|
||||||
p.expect(.lbracket)
|
p.expect(.lbracket)
|
||||||
mut members := []ClassMember{}
|
mut members := []ClassMember{}
|
||||||
for p.peek().type == .identifier {
|
for p.peek().type != .rbracket {
|
||||||
members << p.parse_class_member(p.peek().text)
|
members << p.parse_class_member()
|
||||||
}
|
}
|
||||||
p.expect(.rbracket)
|
p.expect(.rbracket)
|
||||||
p.symbols.define_class(name, members)
|
p.symbols.define_class(name, members)
|
||||||
@@ -706,7 +749,7 @@ fn (mut p Parser) parse_class() ClassDecl {
|
|||||||
fn (mut p Parser) parse_return_stmt() ReturnStmt {
|
fn (mut p Parser) parse_return_stmt() ReturnStmt {
|
||||||
p.expect(.kw_return)
|
p.expect(.kw_return)
|
||||||
|
|
||||||
expr := p.parse_expr(.lowest)
|
expr := p.parse_expr(.base)
|
||||||
|
|
||||||
p.expect(.semicolon)
|
p.expect(.semicolon)
|
||||||
|
|
||||||
@@ -717,7 +760,7 @@ fn (mut p Parser) parse_return_stmt() ReturnStmt {
|
|||||||
|
|
||||||
fn (mut p Parser) parse_if() IfStmt {
|
fn (mut p Parser) parse_if() IfStmt {
|
||||||
p.expect(.kw_if)
|
p.expect(.kw_if)
|
||||||
cond := p.parse_expr(.lowest)
|
cond := p.parse_expr(.base)
|
||||||
if p.get_expr_type(cond) != 'bool' {
|
if p.get_expr_type(cond) != 'bool' {
|
||||||
parse_error('If condition must be of type bool')
|
parse_error('If condition must be of type bool')
|
||||||
}
|
}
|
||||||
@@ -735,7 +778,7 @@ fn (mut p Parser) parse_else() ElseStmt {
|
|||||||
|
|
||||||
fn (mut p Parser) parse_elif() ElifStmt {
|
fn (mut p Parser) parse_elif() ElifStmt {
|
||||||
p.expect(.kw_elif)
|
p.expect(.kw_elif)
|
||||||
cond := p.parse_expr(.lowest)
|
cond := p.parse_expr(.base)
|
||||||
if p.get_expr_type(cond) != 'bool' {
|
if p.get_expr_type(cond) != 'bool' {
|
||||||
parse_error('If condition must be of type bool')
|
parse_error('If condition must be of type bool')
|
||||||
}
|
}
|
||||||
@@ -745,7 +788,7 @@ fn (mut p Parser) parse_elif() ElifStmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_expr_stmt() ExprStmt {
|
fn (mut p Parser) parse_expr_stmt() ExprStmt {
|
||||||
expr := p.parse_expr(.lowest)
|
expr := p.parse_expr(.base)
|
||||||
p.expect(.semicolon)
|
p.expect(.semicolon)
|
||||||
|
|
||||||
return ExprStmt {
|
return ExprStmt {
|
||||||
@@ -793,6 +836,10 @@ fn (mut p Parser) parse_block(no_scope bool) Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) {
|
fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) {
|
||||||
|
p.symbols.define_class('string',[
|
||||||
|
ClassMember{'len', 'int', true}
|
||||||
|
])
|
||||||
|
|
||||||
p.symbols.variable_scopes << map[string]VarSymbolInfo{}
|
p.symbols.variable_scopes << map[string]VarSymbolInfo{}
|
||||||
for p.peek().type != .eof {
|
for p.peek().type != .eof {
|
||||||
p.statements << p.parse_statement()
|
p.statements << p.parse_statement()
|
||||||
|
|||||||
Reference in New Issue
Block a user