Compare commits
3 commits
3f94082477
...
7def9abc5a
Author | SHA1 | Date | |
---|---|---|---|
7def9abc5a | |||
362fc7e3ef | |||
4346636cfa |
5 changed files with 116 additions and 8 deletions
|
@ -42,6 +42,10 @@ fn multwo(num: i32, double_flag: bool) i32 {
|
|||
}
|
||||
}
|
||||
|
||||
fn multwo_with_one(b: i32) i32 {
|
||||
return multwo(b, false) + b;
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return 69 + 69;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,8 @@ pub const TypeSolver = struct {
|
|||
|
||||
// TODO make return type optional and so, skip exprs that
|
||||
// fail to be fully resolved, instead of returning CompileError
|
||||
|
||||
// TODO make the expr ptr a const since we want to implicit cast things
|
||||
pub fn resolveExprType(
|
||||
self: *@This(),
|
||||
ctx: *comp.CompilationContext,
|
||||
|
@ -200,7 +202,6 @@ pub const TypeSolver = struct {
|
|||
// all numeric operations return numeric types
|
||||
.Add, .Sub, .Mul, .Div, .Mod => left_type,
|
||||
|
||||
// TODO check left and right as numeric
|
||||
.Greater, .GreaterEqual, .Less, .LessEqual => blk: {
|
||||
try self.expectSymUnTypeNumeric(left_type);
|
||||
try self.expectSymUnTypeNumeric(right_type);
|
||||
|
@ -226,7 +227,8 @@ pub const TypeSolver = struct {
|
|||
return switch (literal) {
|
||||
.Bool => SymbolUnderlyingType{ .Bool = {} },
|
||||
|
||||
// TODO determine its i64 depending of parseInt results
|
||||
// TODO recast Integer32 as Integer64 if the type we're
|
||||
// checking into is Integer64, but not the other way.
|
||||
.Integer32 => SymbolUnderlyingType{ .Integer32 = {} },
|
||||
.Integer64 => SymbolUnderlyingType{ .Integer64 = {} },
|
||||
.Float => SymbolUnderlyingType{ .Double = {} },
|
||||
|
@ -256,13 +258,31 @@ pub const TypeSolver = struct {
|
|||
var symbol = try ctx.fetchGlobalSymbol(func_name, .Function);
|
||||
var func_sym = symbol.Function;
|
||||
|
||||
// TODO check parameter type mismatches between
|
||||
// call.arguments and func_sym.parameters
|
||||
for (call.arguments.toSlice()) |arg_expr, idx| {
|
||||
var param_type = func_sym.parameter_list.at(idx);
|
||||
var arg_type = try self.resolveExprType(ctx, &arg_expr);
|
||||
|
||||
self.expectSymUnTypeEqual(arg_type, param_type) catch {
|
||||
self.doError(
|
||||
"Expected parameter {} to be {}, got {}",
|
||||
idx,
|
||||
@tagName(comp.SymbolUnderlyingTypeEnum(param_type)),
|
||||
@tagName(comp.SymbolUnderlyingTypeEnum(arg_type)),
|
||||
);
|
||||
|
||||
return CompileError.TypeError;
|
||||
};
|
||||
}
|
||||
|
||||
return func_sym.return_type;
|
||||
},
|
||||
|
||||
// TODO analysis for .Variable
|
||||
.Variable => |vari| {
|
||||
self.setErrToken(vari);
|
||||
var metadata = try ctx.resolveVarType(vari.lexeme);
|
||||
try ctx.insertMetadata(expr, metadata);
|
||||
return metadata.typ;
|
||||
},
|
||||
|
||||
.Get => |get| {
|
||||
var target = get.target.*;
|
||||
|
|
|
@ -141,6 +141,11 @@ pub const SetExpr = struct {
|
|||
value: *Expr,
|
||||
};
|
||||
|
||||
pub const VariableExpr = struct {
|
||||
tok: Token,
|
||||
metadata: ?*comp.VariableMetadata = null,
|
||||
};
|
||||
|
||||
pub const Expr = union(ExprType) {
|
||||
Assign: AssignExpr,
|
||||
|
||||
|
@ -150,6 +155,7 @@ pub const Expr = union(ExprType) {
|
|||
Struct: StructExpr,
|
||||
|
||||
Variable: Token,
|
||||
|
||||
Grouping: *Expr,
|
||||
Call: CallExpr,
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
const std = @import("std");
|
||||
const ast = @import("ast.zig");
|
||||
|
||||
pub const CompilationError = error{TypeError};
|
||||
pub const CompilationError = error{
|
||||
TypeError,
|
||||
UnknownName,
|
||||
};
|
||||
|
||||
pub const SymbolTable = std.hash_map.StringHashMap(SymbolData);
|
||||
pub const TypeList = std.ArrayList(SymbolUnderlyingType);
|
||||
|
@ -76,6 +79,8 @@ 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,
|
||||
parameter_list: TypeList,
|
||||
|
||||
scope: *Scope,
|
||||
|
||||
/// Find a given identifier in the function. Can resolve to either a parameter
|
||||
|
@ -123,6 +128,31 @@ const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
|
|||
|
||||
const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool };
|
||||
|
||||
const Using = enum {
|
||||
Scope,
|
||||
Function,
|
||||
};
|
||||
|
||||
pub const VariableMetadata = struct {
|
||||
typ: SymbolUnderlyingType,
|
||||
|
||||
using: Using,
|
||||
|
||||
from_scope: ?*Scope = null,
|
||||
from_function: ?*FunctionSymbol = null,
|
||||
|
||||
pub fn withScope(scope: *Scope, typ: SymbolUnderlyingType) VariableMetadata {
|
||||
return VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope };
|
||||
}
|
||||
|
||||
pub fn withParam(func: *FunctionSymbol, typ: SymbolUnderlyingType) VariableMetadata {
|
||||
return VariableMetadata{ .typ = typ, .from_function = func, .using = .Function };
|
||||
}
|
||||
};
|
||||
|
||||
// TODO rm const?
|
||||
pub const VariableMetadataMap = std.AutoHashMap(*const ast.Expr, VariableMetadata);
|
||||
|
||||
/// Represents the context for a full compiler run.
|
||||
/// This is used to manage the symbol table for the compilation unit, etc.
|
||||
pub const CompilationContext = struct {
|
||||
|
@ -132,13 +162,21 @@ pub const CompilationContext = struct {
|
|||
cur_function: ?*FunctionSymbol = null,
|
||||
current_scope: ?*Scope = null,
|
||||
|
||||
metadata_map: VariableMetadataMap,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) CompilationContext {
|
||||
return CompilationContext{
|
||||
.allocator = allocator,
|
||||
.symbol_table = SymbolTable.init(allocator),
|
||||
.metadata_map = VariableMetadataMap.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This()) void {
|
||||
self.symbol_table.deinit();
|
||||
self.metadata_map.deinit();
|
||||
}
|
||||
|
||||
/// Create a new scope out of the current one and set it as the current.
|
||||
pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
|
||||
if (self.current_scope == null) {
|
||||
|
@ -239,6 +277,7 @@ pub const CompilationContext = struct {
|
|||
.decl = decl,
|
||||
.return_type = ret_type,
|
||||
.parameters = type_map,
|
||||
.parameter_list = param_types,
|
||||
.scope = scope,
|
||||
},
|
||||
});
|
||||
|
@ -286,4 +325,43 @@ pub const CompilationContext = struct {
|
|||
|
||||
return sym_kv.?.value;
|
||||
}
|
||||
|
||||
fn resolveVarTypeInScope(
|
||||
self: *@This(),
|
||||
scope_opt: ?*Scope,
|
||||
name: []const u8,
|
||||
) ?VariableMetadata {
|
||||
if (scope_opt == null) return null;
|
||||
var scope = scope_opt.?;
|
||||
|
||||
var kv_opt = scope.env.get(name);
|
||||
if (kv_opt) |kv| {
|
||||
return VariableMetadata.withScope(scope, kv.value);
|
||||
} else {
|
||||
return self.resolveVarTypeInScope(scope.parent, name);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a given name's type, assuming it is a variable.
|
||||
pub fn resolveVarType(self: *@This(), name: []const u8) !VariableMetadata {
|
||||
var var_type: ?VariableMetadata = null;
|
||||
|
||||
if (self.current_scope) |scope| {
|
||||
var_type = self.resolveVarTypeInScope(scope, name);
|
||||
if (var_type) |typ| return typ;
|
||||
}
|
||||
|
||||
if (self.cur_function) |cur_function| {
|
||||
var kv_opt = cur_function.parameters.get(name);
|
||||
if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value);
|
||||
}
|
||||
|
||||
std.debug.warn("Unknown name {}\n", name);
|
||||
return CompilationError.UnknownName;
|
||||
}
|
||||
|
||||
pub fn insertMetadata(self: *@This(), ptr: *const ast.Expr, metadata: VariableMetadata) !void {
|
||||
std.debug.assert(ast.ExprType(ptr.*) == .Variable);
|
||||
_ = try self.metadata_map.put(ptr, metadata);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -412,9 +412,9 @@ pub const Parser = struct {
|
|||
return expr;
|
||||
}
|
||||
|
||||
fn mkVariable(self: *Parser, variable: Token) !*ast.Expr {
|
||||
fn mkVariable(self: *Parser, tok: Token) !*ast.Expr {
|
||||
var expr = try self.allocator.create(Expr);
|
||||
expr.* = Expr{ .Variable = variable };
|
||||
expr.* = Expr{ .Variable = tok };
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue