Compare commits
No commits in common. "8065d0d905427bcfee5145fe0be2576ae02caa4f" and "e69451cdd9e8f7fcb176a09c8264dea9f3c4c7cc" have entirely different histories.
8065d0d905
...
e69451cdd9
9 changed files with 54 additions and 118 deletions
|
@ -1,9 +1,6 @@
|
|||
const (
|
||||
test_var = 1 + 3
|
||||
)
|
||||
// import std;
|
||||
|
||||
fn f() i32 {
|
||||
var a = 3;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -11,6 +8,10 @@ fn f2() i32 {
|
|||
return f() + 2;
|
||||
}
|
||||
|
||||
const (
|
||||
piss = 1 + 3
|
||||
)
|
||||
|
||||
enum B {
|
||||
a
|
||||
b
|
||||
|
|
27
src/ast.zig
27
src/ast.zig
|
@ -97,6 +97,9 @@ pub const AssignExpr = struct {
|
|||
pub const ExprType = enum {
|
||||
Assign,
|
||||
|
||||
// vardecls as expressions is a hack
|
||||
VarDecl,
|
||||
|
||||
Binary,
|
||||
Unary,
|
||||
Literal,
|
||||
|
@ -109,6 +112,11 @@ pub const ExprType = enum {
|
|||
Set,
|
||||
};
|
||||
|
||||
pub const VarDecl = struct {
|
||||
assign: AssignExpr,
|
||||
mutable: bool = false,
|
||||
};
|
||||
|
||||
pub const CallExpr = struct {
|
||||
callee: *Expr,
|
||||
paren: Token,
|
||||
|
@ -140,6 +148,7 @@ pub const SetExpr = struct {
|
|||
|
||||
pub const Expr = union(ExprType) {
|
||||
Assign: AssignExpr,
|
||||
VarDecl: VarDecl,
|
||||
|
||||
Binary: BinaryExpr,
|
||||
Unary: UnaryExpr,
|
||||
|
@ -172,16 +181,10 @@ pub const ForStmt = struct {
|
|||
block: Block,
|
||||
};
|
||||
|
||||
pub const VarDeclStmt = struct {
|
||||
name: Token,
|
||||
value: *Expr,
|
||||
};
|
||||
|
||||
pub const Stmt = union(enum) {
|
||||
Expr: *Expr,
|
||||
Println: *Expr,
|
||||
|
||||
VarDecl: VarDeclStmt,
|
||||
If: IfStmt,
|
||||
Loop: LoopStmt,
|
||||
For: ForStmt,
|
||||
|
@ -258,18 +261,6 @@ pub const Stmt = union(enum) {
|
|||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
pub fn mkVarDecl(allocator: *std.mem.Allocator, name: Token, value: *Expr) !*Stmt {
|
||||
var stmt = try allocator.create(Stmt);
|
||||
stmt.* = Stmt{
|
||||
.VarDecl = VarDeclStmt{
|
||||
.name = name,
|
||||
.value = value,
|
||||
},
|
||||
};
|
||||
|
||||
return stmt;
|
||||
}
|
||||
};
|
||||
|
||||
pub const FieldList = std.ArrayList(StructField);
|
||||
|
|
|
@ -239,6 +239,18 @@ pub fn printExpr(expr: *const Expr) void {
|
|||
|
||||
.Variable => |token| std.debug.warn("{}", token.lexeme),
|
||||
|
||||
.VarDecl => |decl| {
|
||||
if (decl.mutable) {
|
||||
std.debug.warn("(mut ");
|
||||
} else {
|
||||
std.debug.warn("(");
|
||||
}
|
||||
|
||||
std.debug.warn("let {} ", decl.assign.name.lexeme);
|
||||
printExpr(decl.assign.value);
|
||||
std.debug.warn(")");
|
||||
},
|
||||
|
||||
.Assign => |assign| {
|
||||
std.debug.warn("(set ");
|
||||
std.debug.warn("{} ", assign.name.lexeme);
|
||||
|
@ -293,12 +305,6 @@ pub fn printStmt(ident: usize, stmt: *const Stmt) void {
|
|||
.Println => |expr| printSimpleOp("println", expr),
|
||||
.Expr => |expr| printExpr(expr),
|
||||
|
||||
.VarDecl => |decl| {
|
||||
std.debug.warn("(let {} ", decl.name.lexeme);
|
||||
printExpr(decl.value);
|
||||
std.debug.warn(")");
|
||||
},
|
||||
|
||||
.If => |ifstmt| {
|
||||
std.debug.warn("(if ");
|
||||
printExpr(ifstmt.condition);
|
||||
|
|
|
@ -79,6 +79,8 @@ pub const Codegen = struct {
|
|||
|
||||
// TODO VarDecl add things to the symbol table
|
||||
// TODO Assign modify symbol table
|
||||
|
||||
// TODO Calls fetch symbol table, check arity of it at codegen level
|
||||
return switch (expr.*) {
|
||||
|
||||
// TODO handle all literals, construct llvm values for them
|
||||
|
@ -166,6 +168,7 @@ pub const Codegen = struct {
|
|||
|
||||
.Call => |call| {
|
||||
const name = call.callee.*.Variable.lexeme;
|
||||
//var sym = try self.ctx.fetchGlobalSymbol(func_name, .Function);
|
||||
|
||||
var llvm_func = self.llvm_table.get(name);
|
||||
if (llvm_func == null) {
|
||||
|
@ -173,6 +176,7 @@ pub const Codegen = struct {
|
|||
return CompileError.EmitError;
|
||||
}
|
||||
|
||||
// TODO args
|
||||
var args = LLVMValueList.init(self.allocator);
|
||||
errdefer args.deinit();
|
||||
|
||||
|
@ -192,22 +196,6 @@ pub const Codegen = struct {
|
|||
);
|
||||
},
|
||||
|
||||
// TODO finish this
|
||||
.Assign => |assign| {
|
||||
// TODO find assign.name on the "parent context", we should have
|
||||
// a way to do name resolution that is completely relative to
|
||||
// where we currently are, and go up in scope. so that we find
|
||||
// the LLVMValueRef.
|
||||
|
||||
// we will also need to repeat the step for the type resolver
|
||||
|
||||
//var typ = self.findCurrent(assign.name);
|
||||
var assign_expr = try self.emitExpr(builder, assign.value);
|
||||
|
||||
// TODO rm null
|
||||
return llvm.LLVMBuildStore(builder, null, assign_expr);
|
||||
},
|
||||
|
||||
else => {
|
||||
std.debug.warn("Got unexpected expr {}\n", ast.ExprType(expr.*));
|
||||
return CompileError.EmitError;
|
||||
|
@ -302,7 +290,7 @@ pub const Codegen = struct {
|
|||
},
|
||||
|
||||
else => {
|
||||
std.debug.warn("Got unexpected stmt {}\n", stmt.*);
|
||||
std.debug.warn("Got unexpected statement {}\n", stmt.*);
|
||||
return CompileError.EmitError;
|
||||
},
|
||||
}
|
||||
|
@ -354,6 +342,7 @@ pub const Codegen = struct {
|
|||
llvm.LLVMPositionBuilderAtEnd(builder, entry);
|
||||
|
||||
for (decl.body.toSlice()) |stmt| {
|
||||
// TODO custom function context for us
|
||||
try self.emitStmt(builder, &stmt);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,6 @@ pub const SymbolUnderlyingType = union(SymbolUnderlyingTypeEnum) {
|
|||
Enum: []const u8,
|
||||
};
|
||||
|
||||
pub const Scope = std.StringHashMap(SymbolUnderlyingType);
|
||||
pub const Environment = struct {
|
||||
parent: *Environment,
|
||||
scope: Scope,
|
||||
};
|
||||
|
||||
// functions, for our purposes, other than symbols, have:
|
||||
// - a return type
|
||||
// - TODO parameters
|
||||
|
@ -45,7 +39,7 @@ pub const FunctionSymbol = struct {
|
|||
/// Parameters for a function are also a table instead of an ArrayList
|
||||
/// because we want to resolve identifiers to them.
|
||||
parameters: UnderlyingTypeMap,
|
||||
env: *Environment,
|
||||
symbols: SymbolTable,
|
||||
|
||||
/// Find a given identifier in the function. Can resolve to either a parameter
|
||||
pub fn findSymbol(self: *const @This(), identifier: []const u8) ?SymbolData {
|
||||
|
|
|
@ -295,6 +295,21 @@ pub const Parser = struct {
|
|||
return expr;
|
||||
}
|
||||
|
||||
fn mkVarDecl(self: *@This(), name: Token, value: *Expr, mutable: bool) !*Expr {
|
||||
var vardecl = try self.allocator.create(Expr);
|
||||
vardecl.* = Expr{
|
||||
.VarDecl = ast.VarDecl{
|
||||
.assign = ast.AssignExpr{
|
||||
.name = name,
|
||||
.value = value,
|
||||
},
|
||||
.mutable = mutable,
|
||||
},
|
||||
};
|
||||
|
||||
return vardecl;
|
||||
}
|
||||
|
||||
fn mkCall(self: *@This(), callee: *Expr, paren: Token, args: ast.ExprList) !*Expr {
|
||||
var expr = try self.allocator.create(Expr);
|
||||
expr.* = Expr{
|
||||
|
@ -701,7 +716,6 @@ pub const Parser = struct {
|
|||
|
||||
fn parseStmt(self: *@This()) anyerror!*Stmt {
|
||||
return switch (self.peek().typ) {
|
||||
.Var => try self.parseVarDecl(),
|
||||
.If => try self.parseIfStmt(),
|
||||
.Loop => try self.parseLoop(),
|
||||
.For => try self.parseForStmt(),
|
||||
|
@ -711,14 +725,6 @@ pub const Parser = struct {
|
|||
};
|
||||
}
|
||||
|
||||
fn parseVarDecl(self: *@This()) !*Stmt {
|
||||
_ = try self.consumeSingle(.Var);
|
||||
var name = try self.consumeSingle(.Identifier);
|
||||
_ = try self.consumeSingle(.Equal);
|
||||
var value = try self.parseExpr();
|
||||
return try Stmt.mkVarDecl(self.allocator, name, value);
|
||||
}
|
||||
|
||||
/// Parse a list of statements.
|
||||
fn parseBlock(self: *@This()) !*Node {
|
||||
var stmts = try self.parseBlockInternal(ast.StmtList);
|
||||
|
@ -834,8 +840,8 @@ pub const Parser = struct {
|
|||
|
||||
fn parseAssignment(self: *@This()) anyerror!*Expr {
|
||||
// there can be two assignments coming out of this function:
|
||||
// - an assignment to a variable with =
|
||||
// - an update to a variable with +=, -=
|
||||
// - a mutable/immutable variable declaration with :=
|
||||
// - an assignment to a variable with =, +=, -=
|
||||
|
||||
// one is a statement, other is an expression. since the normal result
|
||||
// of this is an Expr, we wrap variable assignments in an Expr as well.
|
||||
|
@ -849,7 +855,7 @@ pub const Parser = struct {
|
|||
var expr = try self.parseOr();
|
||||
|
||||
if (self.compareAnyOf(&[_]TokenType{
|
||||
.Equal, .PlusEqual, .MinusEqual, .StarEqual,
|
||||
.ColonEqual, .Equal, .PlusEqual, .MinusEqual, .StarEqual,
|
||||
.SlashEqual,
|
||||
})) {
|
||||
return try self.finishAssignment(expr, mutable);
|
||||
|
@ -865,7 +871,8 @@ pub const Parser = struct {
|
|||
var value = try self.parseAssignment();
|
||||
|
||||
// expr can be a (Variable|Set)
|
||||
// op_tok can be one of two categories:
|
||||
// op_tok can be one of three categories:
|
||||
// - ColonEqual, parses to VarDecl (only when expr = Variable)
|
||||
// - Equal, parses to (Assign|Set)
|
||||
// - Inplace (+=, -=, *=, /=), parses to (Assign|Set)
|
||||
|
||||
|
@ -886,6 +893,7 @@ pub const Parser = struct {
|
|||
switch (expr.*) {
|
||||
.Variable => {
|
||||
switch (op_tok.typ) {
|
||||
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
|
||||
.Equal => return try self.mkAssign(expr.Variable, value),
|
||||
|
||||
.PlusEqual, .MinusEqual, .StarEqual, .SlashEqual => {
|
||||
|
@ -901,7 +909,6 @@ pub const Parser = struct {
|
|||
|
||||
.Get => |get| {
|
||||
switch (op_tok.typ) {
|
||||
// TODO remove .ColonEqual from language
|
||||
.ColonEqual => {
|
||||
return self.doError("can not initialize struct field");
|
||||
},
|
||||
|
|
|
@ -54,7 +54,6 @@ const keywords = [_][]const u8{
|
|||
"pub",
|
||||
"and",
|
||||
"or",
|
||||
"var",
|
||||
};
|
||||
|
||||
const keyword_ttypes = [_]TokenType{
|
||||
|
@ -87,12 +86,9 @@ const keyword_ttypes = [_]TokenType{
|
|||
.Pub,
|
||||
.And,
|
||||
.Or,
|
||||
.Var,
|
||||
};
|
||||
|
||||
fn getKeyword(keyword: []const u8) ?TokenType {
|
||||
std.debug.assert(keywords.len == keyword_ttypes.len);
|
||||
|
||||
for (keywords) |kw, idx| {
|
||||
if (std.mem.eql(u8, keyword, kw)) {
|
||||
return keyword_ttypes[idx];
|
||||
|
|
|
@ -77,7 +77,6 @@ pub const TokenType = enum {
|
|||
|
||||
Println,
|
||||
Pub,
|
||||
Var,
|
||||
|
||||
EOF,
|
||||
};
|
||||
|
|
|
@ -170,45 +170,6 @@ pub const TypeSolver = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stmtPass(
|
||||
self: *@This(),
|
||||
ctx: *comp.CompilationContext,
|
||||
stmt: ast.Stmt,
|
||||
) !void {
|
||||
switch (stmt) {
|
||||
|
||||
// There are no side-effects to the type system when the statement
|
||||
// is just an expression or a println. we just resolve it
|
||||
// to ensure we dont have type errors.
|
||||
.Expr => |expr_ptr| try self.resolveExprType(ctx, expr_ptr),
|
||||
.Println => |expr_ptr| try self.resolveExprType(ctx, expr_ptr),
|
||||
|
||||
// VarDecl means we check the type of the expression and
|
||||
// insert it into the context, however we need to know a pointer
|
||||
// to where we are, scope-wise, we don't have that info here,
|
||||
// so it should be implicit into the context.
|
||||
.VarDecl => @panic("TODO vardecl"),
|
||||
|
||||
// If create two scopes for each branch of the if
|
||||
.If => @panic("TODO ifstmt"),
|
||||
|
||||
// Loop (creates 1 scope) asserts that the expression
|
||||
// type is a bool
|
||||
.Loop => @panic("TODO loop"),
|
||||
|
||||
// For (creates 1 scope) receives arrays, which we dont have yet
|
||||
.For => @panic("TODO for"),
|
||||
|
||||
// Returns dont cause any type system things as they deal with
|
||||
// values, however, we must ensure that the expression type
|
||||
// matches the function type (must fetch from context, or we could
|
||||
// pull a hack with err contexts, lol)
|
||||
.Return => @panic("TODO return"),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nodePass(
|
||||
self: *@This(),
|
||||
ctx: *comp.CompilationContext,
|
||||
|
@ -233,14 +194,6 @@ pub const TypeSolver = struct {
|
|||
try parameters.append(param_type.?);
|
||||
}
|
||||
|
||||
// TODO scopes: bump scope
|
||||
|
||||
for (decl.body.toSlice()) |stmt| {
|
||||
try self.stmtPass(ctx, stmt);
|
||||
}
|
||||
|
||||
// TODO scopes: down scope
|
||||
|
||||
// TODO symbols and scope resolution, that's
|
||||
// its own can of worms
|
||||
var symbols = comp.SymbolTable.init(self.allocator);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue