Compare commits

...

2 Commits

Author SHA1 Message Date
Luna c2499f96c9 add struct intialization 2019-08-26 11:59:32 -03:00
Luna 19fd9daebf add structs 2019-08-26 10:49:43 -03:00
5 changed files with 171 additions and 18 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,14 +36,15 @@ fn main(a int) int {
return 23
//p := Point{
// x: 10
// y: 20
//}
p := Point.{
x: 10
y: 20
}
//println(p.x)
}
//struct Point {
// x int
// y int
//}
struct Point {
x int
y int
}

View File

@ -12,6 +12,7 @@ pub const NodeType = enum {
Root,
FnDecl,
ConstDecl,
Struct,
Block,
Expr,
Stmt,
@ -76,6 +77,8 @@ pub const ExprType = enum {
Literal,
Variable,
Call,
Struct,
Grouping,
};
@ -90,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,
@ -98,6 +113,7 @@ pub const Expr = union(ExprType) {
Unary: UnaryExpr,
Logical: LogicalExpr,
Literal: LiteralExpr,
Struct: StructExpr,
Variable: Token,
Grouping: *Expr,
@ -184,19 +200,46 @@ pub const Stmt = union(enum) {
}
};
pub const FieldList = std.ArrayList(StructField);
pub const StructField = struct {
name: Token,
typ: Token,
mutable: bool = true,
public: bool = true,
};
pub const Struct = struct {
name: Token,
fields: FieldList,
};
pub const Node = union(NodeType) {
Root: NodeList,
FnDecl: FnDecl,
ConstDecl: ConstList,
Struct: Struct,
Block: StmtList,
Expr: *Expr,
Stmt: *Stmt,
};
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
var node = try allocator.create(Node);
node.* = Node{ .Root = NodeList.init(allocator) };
return node;
}
pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
var node = try allocator.create(Node);
node.* = Node{ .Root = NodeList.init(allocator) };
return node;
}
pub fn mkStructDecl(allocator: *std.mem.Allocator, name: Token, fields: FieldList) !*Node {
var node = try allocator.create(Node);
node.* = Node{
.Struct = Struct{
.name = name,
.fields = fields,
},
};
return node;
}
};

View File

@ -74,12 +74,31 @@ pub fn printNode(node: *Node, ident: usize) void {
std.debug.warn("\n");
},
.Stmt => |stmt| blk: {
.Stmt => |stmt| {
printIdent(ident);
printStmt(ident, stmt);
std.debug.warn("\n");
},
.Struct => |struc| {
print(ident, "(struct {} (\n", struc.name.lexeme);
for (struc.fields.toSlice()) |field| {
printIdent(ident + 1);
if (field.mutable) {
std.debug.warn("(mut ");
} else {
std.debug.warn("(");
}
if (field.public) {
std.debug.warn("pub ");
}
std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme);
}
print(ident, "))\n");
},
else => {
print(ident, "unknown node: {}\n", node);
},
@ -146,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{
@ -311,7 +323,7 @@ pub const Parser = struct {
}
pub fn parse(self: *Parser) !*ast.Node {
var root = try ast.mkRoot(self.allocator);
var root = try Node.mkRoot(self.allocator);
var token_opt: ?Token = null;
@ -389,11 +401,37 @@ pub const Parser = struct {
return self.mkConstDecl(consts);
}
fn parseStructDecl(self: *@This()) !*Node {
var fields = ast.FieldList.init(self.allocator);
errdefer fields.deinit();
_ = try self.consumeSingle(.Struct);
var name = try self.consumeSingle(.Identifier);
_ = try self.consumeSingle(.LeftBrace);
while (!self.check(.RightBrace)) {
// TODO mut and pub
const field_name = try self.consumeSingle(.Identifier);
const field_type = try self.consumeSingle(.Identifier);
try fields.append(ast.StructField{
.name = field_name,
.typ = field_type,
});
}
_ = try self.consumeSingle(.RightBrace);
return Node.mkStructDecl(self.allocator, name, fields);
}
fn parseTopDecl(self: *@This()) !*Node {
return switch (self.peek().ttype) {
.Fn => try self.parseFnDecl(),
.Const => try self.parseConstDecl(),
// TODO .Struct => try self.parseStructDecl(),
.Struct => try self.parseStructDecl(),
else => |ttype| blk: {
self.doError("(basic) expected fn/const, got {}\n", ttype);
@ -673,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;
}
@ -712,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;