add struct intialization

This commit is contained in:
Luna 2019-08-26 11:59:32 -03:00
parent 19fd9daebf
commit c2499f96c9
5 changed files with 85 additions and 5 deletions

View File

@ -11,6 +11,9 @@ because i can
- `for` is split between `for` and `loop` because my fucking god i cant stand
having *four* different variations of `for`.
- struct initialization is with `Struct.{}`, not `Struct{}`, to remove parsing
ambiguities
## how
```

View File

@ -18,6 +18,7 @@ fn main(a int) int {
println(50)
}
a && b
a || b
@ -35,10 +36,11 @@ fn main(a int) int {
return 23
//p := Point{
// x: 10
// y: 20
//}
p := Point.{
x: 10
y: 20
}
//println(p.x)
}

View File

@ -77,6 +77,8 @@ pub const ExprType = enum {
Literal,
Variable,
Call,
Struct,
Grouping,
};
@ -91,6 +93,18 @@ pub const CallExpr = struct {
arguments: ExprList,
};
pub const StructInit = struct {
field: Token,
expr: *Expr,
};
pub const StructInitList = std.ArrayList(StructInit);
pub const StructExpr = struct {
name: Token,
inits: StructInitList,
};
pub const Expr = union(ExprType) {
Assign: AssignExpr,
VarDecl: VarDecl,
@ -99,6 +113,7 @@ pub const Expr = union(ExprType) {
Unary: UnaryExpr,
Logical: LogicalExpr,
Literal: LiteralExpr,
Struct: StructExpr,
Variable: Token,
Grouping: *Expr,

View File

@ -165,6 +165,18 @@ pub fn printExpr(expr: *Expr) void {
std.debug.warn(")");
},
.Struct => |val| {
std.debug.warn("({} (", val.name.lexeme);
for (val.inits.toSlice()) |init| {
std.debug.warn(" ({} ", init.field.lexeme);
printExpr(init.expr);
std.debug.warn(")");
}
std.debug.warn("))");
},
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
}
}

View File

@ -259,6 +259,18 @@ pub const Parser = struct {
return expr;
}
fn mkStructExpr(self: *@This(), name: Token, args: ast.StructInitList) !*Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
.Struct = ast.StructExpr{
.name = name,
.inits = args,
},
};
return expr;
}
fn mkBool(self: *Parser, val: bool) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{
@ -699,14 +711,21 @@ pub const Parser = struct {
var expr = try self.parsePrimary();
while (true) {
std.debug.warn("maybe fncall / struct: {}\n", self.peek().ttype);
printer.printExpr(expr);
if (self.check(.LeftParen)) {
if (ast.ExprType(expr.*) != .Variable) {
self.doError("cannot call non-variable{}", ast.ExprType(expr.*));
self.doError("cannot call non-variable {}", ast.ExprType(expr.*));
return Result.CompileError;
}
_ = try self.consumeSingle(.LeftParen);
expr = try self.finishCall(expr);
} else if (self.check(.Dot)) {
_ = try self.consumeSingle(.Dot);
_ = try self.consumeSingle(.LeftBrace);
expr = try self.finishStructVal(expr);
} else {
break;
}
@ -738,6 +757,35 @@ pub const Parser = struct {
return self.mkCall(callee, paren, args);
}
fn finishStructVal(self: *@This(), expr: *Expr) !*Expr {
// <expr>{a: 10 b: 10}
// for this to work properly, <expr> must be Variable, since its a type.
if (ast.ExprType(expr.*) != .Variable) {
self.doError("Expected variable for struct type, got {}", ast.ExprType(expr.*));
return Result.CompileError;
}
var inits = ast.StructInitList.init(self.allocator);
errdefer inits.deinit();
while (!self.check(.RightBrace)) {
const field_name = try self.consumeSingle(.Identifier);
// TODO check .Comma for the quick initialization {val,val,val}
_ = try self.consumeSingle(.Colon);
const field_value = (try self.parseExpr()).Expr;
try inits.append(ast.StructInit{
.field = field_name,
.expr = field_value,
});
}
_ = try self.consumeSingle(.RightBrace);
return try self.mkStructExpr(expr.Variable, inits);
}
fn parsePrimary(self: *@This()) !*Expr {
const curtype = self.peek().ttype;
const lexeme = self.peek().lexeme;