Compare commits
5 Commits
c2499f96c9
...
6a52297cce
Author | SHA1 | Date |
---|---|---|
Luna | 6a52297cce | |
Luna | bd036ff961 | |
Luna | 45b027e90f | |
Luna | d55137a7c7 | |
Luna | 0ecfb75081 |
16
README.md
16
README.md
|
@ -1,10 +1,16 @@
|
||||||
# spoodle
|
# vig
|
||||||
|
|
||||||
a vlang parser in zig
|
a [v] parser in zig
|
||||||
|
|
||||||
|
[v]: https://vlang.io
|
||||||
|
|
||||||
|
(will likely be done as a full compiler, who knows, leave a like and subscribe
|
||||||
|
for more epic adventures)
|
||||||
|
|
||||||
## why
|
## why
|
||||||
|
|
||||||
because i can
|
because i want to learn parsers and what best to do it with a language i'm
|
||||||
|
negatively charged towards
|
||||||
|
|
||||||
## variations
|
## variations
|
||||||
|
|
||||||
|
@ -17,7 +23,7 @@ because i can
|
||||||
## how
|
## how
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://gitdab.com/luna/spoodle.git
|
git clone https://gitdab.com/luna/vig.git
|
||||||
cd spoodle
|
cd vig
|
||||||
zig build install --prefix ~/.local/
|
zig build install --prefix ~/.local/
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,7 +2,7 @@ const Builder = @import("std").build.Builder;
|
||||||
|
|
||||||
pub fn build(b: *Builder) void {
|
pub fn build(b: *Builder) void {
|
||||||
const mode = b.standardReleaseOptions();
|
const mode = b.standardReleaseOptions();
|
||||||
const exe = b.addExecutable("spoodle", "src/main.zig");
|
const exe = b.addExecutable("vig", "src/main.zig");
|
||||||
exe.setBuildMode(mode);
|
exe.setBuildMode(mode);
|
||||||
|
|
||||||
const run_cmd = exe.run();
|
const run_cmd = exe.run();
|
||||||
|
|
|
@ -5,6 +5,11 @@ const (
|
||||||
Businesses = 4
|
Businesses = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
fn main(a int) int {
|
fn main(a int) int {
|
||||||
1 + 2 + 3 + 4
|
1 + 2 + 3 + 4
|
||||||
1 + 1 * 1
|
1 + 1 * 1
|
||||||
|
@ -41,10 +46,7 @@ fn main(a int) int {
|
||||||
y: 20
|
y: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
//println(p.x)
|
p.x = 69
|
||||||
}
|
|
||||||
|
|
||||||
struct Point {
|
println(egg.scramble(3).with(cheddar))
|
||||||
x int
|
}
|
||||||
y int
|
|
||||||
}
|
|
||||||
|
|
16
src/ast.zig
16
src/ast.zig
|
@ -80,6 +80,8 @@ pub const ExprType = enum {
|
||||||
Struct,
|
Struct,
|
||||||
|
|
||||||
Grouping,
|
Grouping,
|
||||||
|
Get,
|
||||||
|
Set,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const VarDecl = struct {
|
pub const VarDecl = struct {
|
||||||
|
@ -105,6 +107,17 @@ pub const StructExpr = struct {
|
||||||
inits: StructInitList,
|
inits: StructInitList,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const GetExpr = struct {
|
||||||
|
struc: *Expr,
|
||||||
|
name: Token,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SetExpr = struct {
|
||||||
|
struc: *Expr,
|
||||||
|
field: Token,
|
||||||
|
value: *Expr,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Expr = union(ExprType) {
|
pub const Expr = union(ExprType) {
|
||||||
Assign: AssignExpr,
|
Assign: AssignExpr,
|
||||||
VarDecl: VarDecl,
|
VarDecl: VarDecl,
|
||||||
|
@ -118,6 +131,9 @@ pub const Expr = union(ExprType) {
|
||||||
Variable: Token,
|
Variable: Token,
|
||||||
Grouping: *Expr,
|
Grouping: *Expr,
|
||||||
Call: CallExpr,
|
Call: CallExpr,
|
||||||
|
|
||||||
|
Get: GetExpr,
|
||||||
|
Set: SetExpr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Block = std.ArrayList(*Stmt);
|
pub const Block = std.ArrayList(*Stmt);
|
||||||
|
|
|
@ -4,6 +4,8 @@ const Token = tokens.Token;
|
||||||
|
|
||||||
usingnamespace @import("ast.zig");
|
usingnamespace @import("ast.zig");
|
||||||
|
|
||||||
|
const warn = std.debug.warn;
|
||||||
|
|
||||||
fn printIdent(ident: usize) void {
|
fn printIdent(ident: usize) void {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < ident) : (i += 1) {
|
while (i < ident) : (i += 1) {
|
||||||
|
@ -177,6 +179,20 @@ pub fn printExpr(expr: *Expr) void {
|
||||||
std.debug.warn("))");
|
std.debug.warn("))");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.Get => |get| {
|
||||||
|
warn("(");
|
||||||
|
printExpr(get.struc);
|
||||||
|
warn(".{})", get.name.lexeme);
|
||||||
|
},
|
||||||
|
|
||||||
|
.Set => |set| {
|
||||||
|
warn("(set ");
|
||||||
|
printExpr(set.struc);
|
||||||
|
warn(" {} ", set.field.lexeme);
|
||||||
|
printExpr(set.value);
|
||||||
|
warn(")");
|
||||||
|
},
|
||||||
|
|
||||||
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
|
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,11 @@ pub const Parser = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) !Token {
|
fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) !Token {
|
||||||
if (self.check(ttype)) return try self.nextToken();
|
if (self.check(ttype)) {
|
||||||
|
var tok = self.peek();
|
||||||
|
_ = try self.nextToken();
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
try self.tokenError(self.peek(), msg);
|
try self.tokenError(self.peek(), msg);
|
||||||
return Result.CompileError;
|
return Result.CompileError;
|
||||||
|
@ -271,6 +275,31 @@ pub const Parser = struct {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mkGet(self: *@This(), struc: *Expr, name: Token) !*Expr {
|
||||||
|
var expr = try self.allocator.create(Expr);
|
||||||
|
expr.* = Expr{
|
||||||
|
.Get = ast.GetExpr{
|
||||||
|
.struc = struc,
|
||||||
|
.name = name,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mkSet(self: *@This(), struc: *Expr, field: Token, value: *Expr) !*Expr {
|
||||||
|
var expr = try self.allocator.create(Expr);
|
||||||
|
expr.* = Expr{
|
||||||
|
.Set = ast.SetExpr{
|
||||||
|
.struc = struc,
|
||||||
|
.field = field,
|
||||||
|
.value = value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
fn mkBool(self: *Parser, val: bool) !*ast.Expr {
|
fn mkBool(self: *Parser, val: bool) !*ast.Expr {
|
||||||
var expr = try self.allocator.create(Expr);
|
var expr = try self.allocator.create(Expr);
|
||||||
expr.* = Expr{
|
expr.* = Expr{
|
||||||
|
@ -582,15 +611,28 @@ pub const Parser = struct {
|
||||||
_ = try self.nextToken();
|
_ = try self.nextToken();
|
||||||
value = try self.parseAssignment();
|
value = try self.parseAssignment();
|
||||||
|
|
||||||
if (ast.ExprType(expr.*) != .Variable) {
|
switch (expr.*) {
|
||||||
self.doError("Invalid assignment target");
|
.Variable => {
|
||||||
return Result.CompileError;
|
switch (op.ttype) {
|
||||||
}
|
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
|
||||||
|
.Equal => return try self.mkAssign(expr.Variable, value),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
switch (op.ttype) {
|
.Get => |get| {
|
||||||
.ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
|
if (op.ttype == .ColonEqual) {
|
||||||
.Equal => return try self.mkAssign(expr.Variable, value),
|
self.doError("can not initialize struct field");
|
||||||
else => unreachable,
|
return Result.CompileError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return try self.mkSet(get.struc, get.name, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
else => |expr_typ| {
|
||||||
|
self.doError("Invalid assignment target {}", expr_typ);
|
||||||
|
return Result.CompileError;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,17 +757,18 @@ pub const Parser = struct {
|
||||||
printer.printExpr(expr);
|
printer.printExpr(expr);
|
||||||
|
|
||||||
if (self.check(.LeftParen)) {
|
if (self.check(.LeftParen)) {
|
||||||
if (ast.ExprType(expr.*) != .Variable) {
|
|
||||||
self.doError("cannot call non-variable {}", ast.ExprType(expr.*));
|
|
||||||
return Result.CompileError;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = try self.consumeSingle(.LeftParen);
|
_ = try self.consumeSingle(.LeftParen);
|
||||||
expr = try self.finishCall(expr);
|
expr = try self.finishCall(expr);
|
||||||
} else if (self.check(.Dot)) {
|
} else if (self.check(.Dot)) {
|
||||||
_ = try self.consumeSingle(.Dot);
|
_ = try self.consumeSingle(.Dot);
|
||||||
_ = try self.consumeSingle(.LeftBrace);
|
|
||||||
expr = try self.finishStructVal(expr);
|
if (self.check(.LeftBrace)) {
|
||||||
|
_ = try self.consumeSingle(.LeftBrace);
|
||||||
|
expr = try self.finishStructVal(expr);
|
||||||
|
} else {
|
||||||
|
var name = try self.consume(.Identifier, "Expect property name after '.'");
|
||||||
|
expr = try self.mkGet(expr, name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -752,6 +795,7 @@ pub const Parser = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO shouldnt consume() return the current token, not nextToken?
|
||||||
var paren = try self.consume(.RightParen, "Expected ')' after arguments");
|
var paren = try self.consume(.RightParen, "Expected ')' after arguments");
|
||||||
|
|
||||||
return self.mkCall(callee, paren, args);
|
return self.mkCall(callee, paren, args);
|
||||||
|
|
Loading…
Reference in New Issue