authorchloe caruso <git@paperclover.net> 2024-06-01 19:45:28-07:00
committerchloe caruso <git@paperclover.net> 2024-06-01 19:45:28-07:00
logc92fd86aaae8e8f251562fa54b8ec350542ac294
tree1628c6fc46186ce8eae47cb2f5a97784c1b0d8f0
parentdee1ba048e5633e4475ccf8ec954a787958da354

upgrade zig


18 files changed, 264 insertions(+), 87 deletions(-)

.gitignore+1-1
...@@ -6,5 +6,5 @@...@@ -6,5 +6,5 @@
6# excludesfile = ~/.gitignore6# excludesfile = ~/.gitignore
7#7#
88
9.zig-cache
9zig-out10zig-out
10zig-cache
build.zig+1-1
...@@ -127,7 +127,7 @@ pub fn build(b: *std.Build) void {...@@ -127,7 +127,7 @@ pub fn build(b: *std.Build) void {
127 package.dependOn(&b.addInstallFile(127 package.dependOn(&b.addInstallFile(
128 artifact.getEmittedBin(),128 artifact.getEmittedBin(),
129 b.pathJoin(&.{129 b.pathJoin(&.{
130 "release",130 "package",
131 name,131 name,
132 std.mem.concat(b.allocator, u8, &.{132 std.mem.concat(b.allocator, u8, &.{
133 bin_name,133 bin_name,
build.zig.zon+3-3
...@@ -2,12 +2,12 @@...@@ -2,12 +2,12 @@
2 .name = "",2 .name = "",
3 .version = "0.0.0",3 .version = "0.0.0",
44
5 .minimum_zig_version = "0.12.0",5 .minimum_zig_version = "0.13.0-dev.348+c564a16a0",
66
7 .dependencies = .{7 .dependencies = .{
8 .zg = .{8 .zg = .{
9 .url = "https://codeberg.org/dude_the_builder/zg/archive/16735685fcc3410de361ba3411788ad1fb4fe188.tar.gz",9 .url = "https://codeberg.org/dude_the_builder/zg/archive/c425c9c8511bf92e14b8b612d1d16e774b186f2e.tar.gz",
10 .hash = "1220fe9ac5cdb41833d327a78745614e67d472469f8666567bd8cf9f5847a52b1c51",10 .hash = "1220c79009f1e443b015db4de6e5319432538ead2fea10d271f3f35d3ae83c996789",
11 },11 },
12 .tracer = .{12 .tracer = .{
13 .url = "https://github.com/paperdave/zig-tracer/archive/d4c2eff040e9e69b9f08d2175b315f3055ad7ba3.tar.gz",13 .url = "https://github.com/paperdave/zig-tracer/archive/d4c2eff040e9e69b9f08d2175b315f3055ad7ba3.tar.gz",
doc/language-reference.md+14-11
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1# New Language Project1# New Language Project
22
3This is a high-level, general purpose programming language. It is a mix of Rust, Zig, and JavaScript's great points.3This is a high-level, general purpose programming language.
4
5- **Rust** - Expressive control flow that is easy to write.
6- **Zig** - Execute any code at compile time, everything is an expression.
7- **JavaScript** - Garbage collected values with a versitile type system.
84
9Key goals of this project are:5Key goals of this project are:
106
...@@ -12,6 +8,12 @@ Key goals of this project are:...@@ -12,6 +8,12 @@ Key goals of this project are:
12- **Fast Iteration**: The compiler is designed for quick incremental compilation and hot module reloading.8- **Fast Iteration**: The compiler is designed for quick incremental compilation and hot module reloading.
13- TODO: some more9- TODO: some more
1410
11It primarily focuses on merging some great points of Rust, Zig, and JavaScript's language designs:
12
13- **Rust** - Expressive control flow that is easy to write.
14- **Zig** - Execute any code at compile time, everything is an expression.
15- **JavaScript** - Garbage collected values with a versitile type system.
16
15## Standard Library17## Standard Library
1618
17Currently, there is no standard library. One will be introduced later.19Currently, there is no standard library. One will be introduced later.
...@@ -74,7 +76,7 @@ let hello = hello * world;...@@ -74,7 +76,7 @@ let hello = hello * world;
74var message = "first message";76var message = "first message";
7577
76if @js("Math").random() > 0.5 {78if @js("Math").random() > 0.5 {
77 message = "second message"79 message = "second message";
78}80}
7981
80@js("console").log(message);82@js("console").log(message);
...@@ -110,15 +112,14 @@ fn add(a: int, b: int) -> int {...@@ -110,15 +112,14 @@ fn add(a: int, b: int) -> int {
110}112}
111113
112let print = @js("console").log;114let print = @js("console").log;
113//print("Sum of 2 and 7" + add(2, 7));115print("Sum of 2 and 7" + add(2, 7));
114print(add(2, 7));
115```116```
116117
117> **Bug**: Return types are currently required. Omitting the `-> type` syntax currently makes the return type `void`, but this will be changed in the future to be an inferred return type.118> **Bug**: Return types are currently required. Omitting the `-> type` syntax currently makes the return type `void`, but this will be changed in the future to be an inferred return type.
118119
119The `return` expression can be used within functions to return early.120The `return` expression can be used within functions to return early.
120121
121```lang122```lang:run
122fn something(a: int) -> bool {123fn something(a: int) -> bool {
123 if a == 0 {124 if a == 0 {
124 return false;125 return false;
...@@ -126,6 +127,9 @@ fn something(a: int) -> bool {...@@ -126,6 +127,9 @@ fn something(a: int) -> bool {
126127
127 a > 100128 a > 100
128}129}
130
131let print = @js("console").log;
132print(something(0xFF), something(0));
129```133```
130134
131## Number Literals135## Number Literals
...@@ -143,11 +147,10 @@ A global variable handle can be retrived with `@js`. We've seen this in the hell...@@ -143,11 +147,10 @@ A global variable handle can be retrived with `@js`. We've seen this in the hell
143Many JS-exclusive actions are exposed via built-in functions, such as using `@jsNew` for calling constructors.147Many JS-exclusive actions are exposed via built-in functions, such as using `@jsNew` for calling constructors.
144148
145```lang:run149```lang:run
146let date_constructor = @js("Date");
147let print = @js("console").log;150let print = @js("console").log;
148151
149fn currentYear() -> int {152fn currentYear() -> int {
150 @jsNew(date_constructor).getFullYear()153 @jsNew(@js("Date")).getFullYear()
151}154}
152155
153print(currentYear());156print(currentYear());
src/core/Air.Dump.zig+2-2
...@@ -126,8 +126,8 @@ pub const State = struct {...@@ -126,8 +126,8 @@ pub const State = struct {
126 try tty.setColor(w, .reset);126 try tty.setColor(w, .reset);
127 try w.writeAll(")");127 try w.writeAll(")");
128 },128 },
129 .call => {129 inline .call, .new => |t| {
130 const call: Air.Call = air.instData(.call, inst);130 const call: Air.Call = air.instData(t, inst);
131 const call_data = call.call_data.get(air);131 const call_data = call.call_data.get(air);
132 try w.writeAll("(");132 try w.writeAll("(");
133 try s.dumpRef(w, call.base);133 try s.dumpRef(w, call.base);
src/core/Air.zig+3-2
...@@ -16,6 +16,7 @@ pub const Inst = struct {...@@ -16,6 +16,7 @@ pub const Inst = struct {
16 block,16 block,
17 js_global_ref,17 js_global_ref,
18 call,18 call,
19 new,
19 @"break",20 @"break",
20 @"if",21 @"if",
21 arg,22 arg,
...@@ -45,7 +46,7 @@ pub const Inst = struct {...@@ -45,7 +46,7 @@ pub const Inst = struct {
45 .js_global_ref => InternPool.String.WithLen,46 .js_global_ref => InternPool.String.WithLen,
46 .@"break" => Break,47 .@"break" => Break,
47 .@"if" => If,48 .@"if" => If,
48 .call => Call,49 .call, .new => Call,
49 .arg => Arg,50 .arg => Arg,
50 .field => Field,51 .field => Field,
51 .memory => Memory,52 .memory => Memory,
...@@ -258,7 +259,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Type {...@@ -258,7 +259,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Type {
258259
259pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Type {260pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Type {
260 return switch (air.instTag(index)) {261 return switch (air.instTag(index)) {
261 .js_global_ref => .@"opaque",262 .js_global_ref, .new => .@"opaque",
262263
263 .block => {264 .block => {
264 const items = air.instData(.block, index).slice(air);265 const items = air.instData(.block, index).slice(air);
src/core/Ast.zig+1
...@@ -38,6 +38,7 @@ utf8_source: [:0]const u8,...@@ -38,6 +38,7 @@ utf8_source: [:0]const u8,
3838
39tokens: Token.List.Slice,39tokens: Token.List.Slice,
40nodes: Node.List.Slice,40nodes: Node.List.Slice,
41/// TODO: Move this to using array.ExtraStore
41extra: []const u32,42extra: []const u32,
4243
43pub const Node = struct {44pub const Node = struct {
src/core/JsLink.zig+44-4
...@@ -152,9 +152,22 @@ fn printDecl(link: *JsLink, decl_index: Decl.Index, writer: anytype) !void {...@@ -152,9 +152,22 @@ fn printDecl(link: *JsLink, decl_index: Decl.Index, writer: anytype) !void {
152 try link.printLocal(@intCast(id), writer);152 try link.printLocal(@intCast(id), writer);
153 if (id != tree.param_count - 1) try writer.writeAll(", ");153 if (id != tree.param_count - 1) try writer.writeAll(", ");
154 }154 }
155 try writer.writeAll(") => {\n");155 try writer.writeAll(") => ");
156 try link.printDeclContents(tree, writer);156
157 try writer.writeAll("};\n");157 const stmts = tree.mainStatements();
158 if (stmts.len == 1 and tree.nodeTag(stmts[0]) == .stmt_return) {
159 if (tree.nodeData(.stmt_return, stmts[0]).operand.unwrap()) |operand| {
160 try link.printExpr(tree, operand, writer);
161 } else {
162 try writer.writeAll("{}");
163 }
164 } else {
165 try writer.writeAll("{\n");
166 try link.printDeclContents(tree, writer);
167 try writer.writeAll("}");
168 }
169
170 try writer.writeAll(";\n");
158}171}
159172
160fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void {173fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void {
...@@ -167,7 +180,12 @@ fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void...@@ -167,7 +180,12 @@ fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void
167 }180 }
168}181}
169182
170fn printBlockContents(link: *JsLink, tree: *const JsTree, list: JsTree.IndexList, writer: anytype) !void {183fn printBlockContents(
184 link: *JsLink,
185 tree: *const JsTree,
186 list: JsTree.IndexList,
187 writer: anytype,
188) !void {
171 var t = tracer.trace(@src());189 var t = tracer.trace(@src());
172 defer t.end();190 defer t.end();
173191
...@@ -377,6 +395,28 @@ fn printExprLevel(...@@ -377,6 +395,28 @@ fn printExprLevel(
377395
378 try writer.writeAll(")");396 try writer.writeAll(")");
379 },397 },
398 .new => {
399 const call: JsTree.Call = tree.nodeData(.new, node);
400 const args = call.args.get(tree);
401
402 if (Level.new.needsParens(level))
403 try writer.writeAll("(");
404 try writer.writeAll("new ");
405 try link.printExpr(tree, call.base, writer);
406
407 if (args.len > 0) {
408 try writer.writeAll("(");
409
410 for (args.slice(tree), 0..) |arg, i| {
411 if (i != 0) try writer.writeAll(", ");
412 try link.printExpr(tree, arg, writer);
413 }
414
415 try writer.writeAll(")");
416 }
417 if (Level.new.needsParens(level))
418 try writer.writeAll(")");
419 },
380420
381 .field => {421 .field => {
382 const field: JsTree.Field = tree.nodeData(.field, node);422 const field: JsTree.Field = tree.nodeData(.field, node);
src/core/JsNodeGen.zig+4-3
...@@ -260,8 +260,8 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {...@@ -260,8 +260,8 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
260 try c.markExpression(inst, node);260 try c.markExpression(inst, node);
261 },261 },
262262
263 .call => {263 inline .call, .new => |tag| {
264 const data: Air.Call = c.air.instData(.call, inst);264 const data: Air.Call = c.air.instData(tag, inst);
265 const call_data = data.call_data.get(c.air);265 const call_data = data.call_data.get(c.air);
266266
267 try c.extra.list.ensureUnusedCapacity(c.gpa, call_data.args.len);267 try c.extra.list.ensureUnusedCapacity(c.gpa, call_data.args.len);
...@@ -274,7 +274,7 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {...@@ -274,7 +274,7 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
274 dest.* = @intFromEnum(try c.fetchExpression(arg));274 dest.* = @intFromEnum(try c.fetchExpression(arg));
275 }275 }
276276
277 const node = try c.add(.call, .{277 const node = try c.add(@field(JsTree.Tag, @tagName(tag)), .{
278 .base = try c.fetchExpression(data.base),278 .base = try c.fetchExpression(data.base),
279 .args = try c.extra.append(c.gpa, JsTree.IndexList, .{279 .args = try c.extra.append(c.gpa, JsTree.IndexList, .{
280 .start = @intCast(start),280 .start = @intCast(start),
...@@ -603,6 +603,7 @@ fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {...@@ -603,6 +603,7 @@ fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {
603 .index => |index| switch (c.air.instTag(index)) {603 .index => |index| switch (c.air.instTag(index)) {
604 .js_global_ref,604 .js_global_ref,
605 .call,605 .call,
606 .new,
606 .arg,607 .arg,
607 .field,608 .field,
608 .add,609 .add,
src/core/JsTree.zig+2-1
...@@ -39,6 +39,7 @@ pub const Tag = enum {...@@ -39,6 +39,7 @@ pub const Tag = enum {
39 gt,39 gt,
40 // exprs40 // exprs
41 call,41 call,
42 new,
42 field,43 field,
43 ternary,44 ternary,
44 // prefix ops45 // prefix ops
...@@ -84,7 +85,7 @@ pub const Tag = enum {...@@ -84,7 +85,7 @@ pub const Tag = enum {
84 .pre_inc,85 .pre_inc,
85 .pre_dec,86 .pre_dec,
86 => Un,87 => Un,
87 .call => Call,88 .call, .new => Call,
88 .field => Field,89 .field => Field,
89 .stmt_if => StmtIf,90 .stmt_if => StmtIf,
90 .stmt_break => StmtBreak,91 .stmt_break => StmtBreak,
src/core/Report.zig+7-5
...@@ -817,11 +817,10 @@ pub const LazyNode = struct {...@@ -817,11 +817,10 @@ pub const LazyNode = struct {
817817
818 switch (teg.instTag(lazy.inst)) {818 switch (teg.instTag(lazy.inst)) {
819 .as => switch (node_tag) {819 .as => switch (node_tag) {
820 .var_decl => {820 .var_decl => switch (lazy.operand) {
821 switch (lazy.operand) {821 .lhs => return data.var_decl.type.unwrap().?,
822 .rhs => return data.var_decl.init,822 .rhs => return data.var_decl.init,
823 else => {},823 else => {},
824 }
825 },824 },
826 else => {},825 else => {},
827 },826 },
...@@ -865,6 +864,9 @@ pub const LazyNode = struct {...@@ -865,6 +864,9 @@ pub const LazyNode = struct {
865 else => fn_decl.params.slice(ctx.ast)[lazy.operand.getArgId()],864 else => fn_decl.params.slice(ctx.ast)[lazy.operand.getArgId()],
866 };865 };
867 },866 },
867 .js => {
868 return base_node;
869 },
868 else => {},870 else => {},
869 }871 }
870872
src/core/Sema.zig+30-3
...@@ -425,6 +425,31 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -425,6 +425,31 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
425 }),425 }),
426 });426 });
427 },427 },
428 .js_new => {
429 const call: Teg.Inst.JsNew = s.code.instPayload(.js_new, in);
430 const base = try s.resolveRefRuntime(call.base);
431
432 const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len);
433 defer s.arena.free(scratch);
434 for (call.args.slice(&s.code), 0..) |arg, i| {
435 const ref = try s.ensureValueRuntime(
436 in.op(Report.Operand.argument(@intCast(i))),
437 try s.resolveRefRuntime(arg),
438 );
439 scratch[i] = ref;
440 }
441
442 const start = s.air_extra.list.items.len;
443 try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));
444
445 return s.addInstRef(.new, .{
446 .base = base,
447 .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{
448 .start = @intCast(start),
449 .len = @intCast(scratch.len),
450 } }),
451 });
452 },
428 .ensure_void => {453 .ensure_void => {
429 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false);454 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false);
430 const t = s.typeOfRef(operand);455 const t = s.typeOfRef(operand);
...@@ -447,9 +472,8 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -447,9 +472,8 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
447 .@"if" => {472 .@"if" => {
448 const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code);473 const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code);
449474
450 const cond = try s.resolveRefRuntime(data.cond);475 const cond_raw = try s.resolveRefRuntime(data.cond);
451476 const cond = try s.coerceRef(in.op(.operand), cond_raw, .bool);
452 // try s.validateType(s.typeOfRef(cond), .bool_type);
453477
454 // If known at comptime, only analyze the taken path478 // If known at comptime, only analyze the taken path
455 if (cond.kind == .value) {479 if (cond.kind == .value) {
...@@ -636,6 +660,9 @@ fn coerceRef(s: *Sema, src: InstOp, value: Air.Inst.Ref, to: Type) !Air.Inst.Ref...@@ -636,6 +660,9 @@ fn coerceRef(s: *Sema, src: InstOp, value: Air.Inst.Ref, to: Type) !Air.Inst.Ref
636 if (from == to) {660 if (from == to) {
637 return value;661 return value;
638 }662 }
663 if (from == .@"opaque") {
664 return value;
665 }
639 const index = switch (value.decode()) {666 const index = switch (value.decode()) {
640 .value => |v| return (try s.coerceValue(src, v, to)).toAir(),667 .value => |v| return (try s.coerceValue(src, v, to)).toAir(),
641 .index => |index| index,668 .index => |index| index,
src/core/Teg.Dump.zig+8
...@@ -186,6 +186,14 @@ const State = struct {...@@ -186,6 +186,14 @@ const State = struct {
186 try s.dumpRefMarkerList(writer, call.args.slice(teg), '[', ']');186 try s.dumpRefMarkerList(writer, call.args.slice(teg), '[', ']');
187 try writer.writeAll(")");187 try writer.writeAll(")");
188 },188 },
189 .js_new => {
190 const call: Teg.Inst.JsNew = teg.instData(.js_new, inst).extra_index.get(teg);
191 try writer.writeAll("(");
192 try s.dumpRefMarker(writer, call.base);
193 try writer.writeAll(",");
194 try s.dumpRefMarkerList(writer, call.args.slice(teg), '[', ']');
195 try writer.writeAll(")");
196 },
189 .load_decl => {197 .load_decl => {
190 const call: Teg.Inst.StrNode = teg.instData(.load_decl, inst);198 const call: Teg.Inst.StrNode = teg.instData(.load_decl, inst);
191199
src/core/Teg.zig+8
...@@ -72,6 +72,8 @@ pub const Inst = struct {...@@ -72,6 +72,8 @@ pub const Inst = struct {
7272
73 /// Implements the `@js` builtin73 /// Implements the `@js` builtin
74 js,74 js,
75 /// Implements the `@jsNew` builtin
76 js_new,
75 /// Implements the `@import` builtin77 /// Implements the `@import` builtin
76 import,78 import,
77 /// Implements the `@fetch` builtin79 /// Implements the `@fetch` builtin
...@@ -95,6 +97,7 @@ pub const Inst = struct {...@@ -95,6 +97,7 @@ pub const Inst = struct {
95 .load_decl => StrNode,97 .load_decl => StrNode,
96 .param => DataNode,98 .param => DataNode,
97 .store => PlNode(Store),99 .store => PlNode(Store),
100 .js_new => PlNode(JsNew),
98101
99 // Single instruction operand102 // Single instruction operand
100 .memory,103 .memory,
...@@ -307,6 +310,11 @@ pub const Inst = struct {...@@ -307,6 +310,11 @@ pub const Inst = struct {
307 no: Inst.Ref,310 no: Inst.Ref,
308 };311 };
309312
313 pub const JsNew = struct {
314 base: Inst.Ref,
315 args: RefList,
316 };
317
310 /// This will contain trailing data depending on the .kind318 /// This will contain trailing data depending on the .kind
311 pub const Decl = struct {319 pub const Decl = struct {
312 name: NullTerminatedString,320 name: NullTerminatedString,
src/core/Tokenizer.zig+42-10
...@@ -274,7 +274,7 @@ pub const Token = struct {...@@ -274,7 +274,7 @@ pub const Token = struct {
274 utf8_source[token.offset..][0..token.len(utf8_source)];274 utf8_source[token.offset..][0..token.len(utf8_source)];
275 }275 }
276276
277 const keywords = std.ComptimeStringMap(Tag, keywords: {277 const keywords = std.StaticStringMap(Tag).initComptime(keywords: {
278 const fields = std.enums.values(Tag);278 const fields = std.enums.values(Tag);
279 const KV = struct { []const u8, Tag };279 const KV = struct { []const u8, Tag };
280 var kws: [fields.len]KV = undefined;280 var kws: [fields.len]KV = undefined;
...@@ -355,18 +355,33 @@ pub fn next(t: *Tokenizer) !?Token {...@@ -355,18 +355,33 @@ pub fn next(t: *Tokenizer) !?Token {
355 (t.byteAt(3) orelse 0 != '/'))355 (t.byteAt(3) orelse 0 != '/'))
356 {356 {
357 const start = t.pos;357 const start = t.pos;
358 t.pos = @intCast(mem.indexOfScalarPos(u8, t.code, t.pos + 3, '\n') orelse t.code.len);358 t.pos = @intCast(mem.indexOfScalarPos(
359 u8,
360 t.code,
361 t.pos + 3,
362 '\n',
363 ) orelse t.code.len);
359 return .{ .tag = .doc_comment, .offset = start };364 return .{ .tag = .doc_comment, .offset = start };
360 }365 }
361366
362 if (t.byteAt(2) orelse 0 == '!') {367 if (t.byteAt(2) orelse 0 == '!') {
363 const start = t.pos;368 const start = t.pos;
364 t.pos = @intCast(mem.indexOfScalarPos(u8, t.code, t.pos + 2, '\n') orelse t.code.len);369 t.pos = @intCast(mem.indexOfScalarPos(
370 u8,
371 t.code,
372 t.pos + 2,
373 '\n',
374 ) orelse t.code.len);
365 return .{ .tag = .module_doc_comment, .offset = start };375 return .{ .tag = .module_doc_comment, .offset = start };
366 }376 }
367377
368 // skip the comment378 // skip the comment
369 t.pos = @intCast(mem.indexOfScalarPos(u8, t.code, t.pos + 2, '\n') orelse t.code.len);379 t.pos = @intCast(mem.indexOfScalarPos(
380 u8,
381 t.code,
382 t.pos + 2,
383 '\n',
384 ) orelse t.code.len);
370 t.skipWhitespace();385 t.skipWhitespace();
371 continue;386 continue;
372 },387 },
...@@ -376,7 +391,12 @@ pub fn next(t: *Tokenizer) !?Token {...@@ -376,7 +391,12 @@ pub fn next(t: *Tokenizer) !?Token {
376 '\\' => switch (t.nextByte()) {391 '\\' => switch (t.nextByte()) {
377 '\\' => {392 '\\' => {
378 const start = t.pos;393 const start = t.pos;
379 t.pos = @intCast(mem.indexOfScalarPos(u8, t.code, t.pos + 2, '\n') orelse t.code.len);394 t.pos = @intCast(mem.indexOfScalarPos(
395 u8,
396 t.code,
397 t.pos + 2,
398 '\n',
399 ) orelse t.code.len);
380 return .{ .tag = .multiline_string, .offset = start };400 return .{ .tag = .multiline_string, .offset = start };
381 },401 },
382 else => return t.maybeUTF8Error(error.InvalidSyntax),402 else => return t.maybeUTF8Error(error.InvalidSyntax),
...@@ -607,8 +627,11 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {...@@ -607,8 +627,11 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {
607 else => unreachable,627 else => unreachable,
608 }628 }
609629
630 const start = t.pos;
631 var tag: Token.Tag = .number_int;
632
610 // Parse Hex, Binary, Octal numbers633 // Parse Hex, Binary, Octal numbers
611 if (t.byte() == '0') {634 if (t.byte() == '0') alt_base: {
612 switch (t.nextByte()) {635 switch (t.nextByte()) {
613 'x', 'X' => {636 'x', 'X' => {
614 t.pos += 2;637 t.pos += 2;
...@@ -622,12 +645,21 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {...@@ -622,12 +645,21 @@ fn tokenizeNumber(t: *Tokenizer) !?Token {
622 t.pos += 2;645 t.pos += 2;
623 try t.consumeIntegerRadix(.octal);646 try t.consumeIntegerRadix(.octal);
624 },647 },
625 else => {},648 '0' => @panic("TODO: no double zero"),
649 else => break :alt_base,
626 }650 }
627 }
628651
629 const start = t.pos;652 // after numbers must be a valid word break the above returns are right
630 var tag: Token.Tag = .number_int;653 // before parsing `.` so those can be unchecked.
654 if (try t.isAtIdentifierStart()) {
655 return error.InvalidSyntax;
656 }
657
658 return .{
659 .tag = tag,
660 .offset = start,
661 };
662 }
631663
632 if (t.byte() == '.') {664 if (t.byte() == '.') {
633 t.pos += 1;665 t.pos += 1;
src/core/Transform.zig+52-26
...@@ -216,7 +216,7 @@ const BlockContext = struct {...@@ -216,7 +216,7 @@ const BlockContext = struct {
216216
217const Liveness = enum { alive, dead };217const Liveness = enum { alive, dead };
218218
219const BuiltInIds = std.ComptimeStringMap(Inst.Ref, .{219const BuiltInIds = std.StaticStringMap(Inst.Ref).initComptime(.{
220 .{ "void", .void },220 .{ "void", .void },
221 .{ "true", .bool_true },221 .{ "true", .bool_true },
222 .{ "false", .bool_false },222 .{ "false", .bool_false },
...@@ -571,7 +571,7 @@ pub const Builtin = enum {...@@ -571,7 +571,7 @@ pub const Builtin = enum {
571 compile_error,571 compile_error,
572 type_of,572 type_of,
573573
574 const map = std.ComptimeStringMap(Builtin, .{574 const map = std.StaticStringMap(Builtin).initComptime(.{
575 // sort-lines: start575 // sort-lines: start
576 .{ "compileError", .compile_error },576 .{ "compileError", .compile_error },
577 .{ "fetch", .fetch },577 .{ "fetch", .fetch },
...@@ -602,6 +602,30 @@ pub const Builtin = enum {...@@ -602,6 +602,30 @@ pub const Builtin = enum {
602 });602 });
603 }603 }
604604
605 fn builtin_jsNew(t: *Transform, decl: BlockContext, node: NodeIndex, args: []const NodeIndex) !?Inst.Ref {
606 const trace = tracer.trace(@src());
607 defer trace.end();
608
609 if (args.len == 0) {
610 try t.report.err(.builtin_mismatch_args, .{ .node = node, .args = 1 });
611 return .void;
612 }
613
614 const base = try t.transformExpression(decl, args[0]) orelse return null;
615 const args_list = try t.transformCallArgs(decl, args[1..]) orelse return null;
616
617 return try t.addInstRef(.{
618 .tag = .js_new,
619 .data = EncodedData.encode(.js_new, .{
620 .src_node = decl.nodeOffset(args[0]),
621 .extra_index = try t.extra.append(t.gpa, Inst.JsNew, .{
622 .base = base,
623 .args = args_list,
624 }),
625 }),
626 });
627 }
628
605 fn builtin_compileError(t: *Transform, decl: BlockContext, node: NodeIndex, args: []const NodeIndex) !?Inst.Ref {629 fn builtin_compileError(t: *Transform, decl: BlockContext, node: NodeIndex, args: []const NodeIndex) !?Inst.Ref {
606 const trace = tracer.trace(@src());630 const trace = tracer.trace(@src());
607 defer trace.end();631 defer trace.end();
...@@ -616,7 +640,7 @@ pub const Builtin = enum {...@@ -616,7 +640,7 @@ pub const Builtin = enum {
616640
617 return try t.addInstRef(.{641 return try t.addInstRef(.{
618 .tag = .compile_error,642 .tag = .compile_error,
619 .data = EncodedData.encode(.js, .{643 .data = EncodedData.encode(.compile_error, .{
620 .src_node = decl.nodeOffset(node),644 .src_node = decl.nodeOffset(node),
621 .operand = source,645 .operand = source,
622 }),646 }),
...@@ -637,7 +661,7 @@ pub const Builtin = enum {...@@ -637,7 +661,7 @@ pub const Builtin = enum {
637661
638 return try t.addInstRef(.{662 return try t.addInstRef(.{
639 .tag = .type_of,663 .tag = .type_of,
640 .data = EncodedData.encode(.js, .{664 .data = EncodedData.encode(.type_of, .{
641 .src_node = decl.nodeOffset(node),665 .src_node = decl.nodeOffset(node),
642 .operand = source,666 .operand = source,
643 }),667 }),
...@@ -932,6 +956,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -932,6 +956,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
932956
933 return switch (builtin) {957 return switch (builtin) {
934 .js => Builtin.builtin_js(t, decl, node, args),958 .js => Builtin.builtin_js(t, decl, node, args),
959 .js_new => Builtin.builtin_jsNew(t, decl, node, args),
935 // .import => Builtin.import(t, decl, node, args),960 // .import => Builtin.import(t, decl, node, args),
936 // .fetch => Builtin.fetch(t, decl, node, args),961 // .fetch => Builtin.fetch(t, decl, node, args),
937 .compile_error => Builtin.builtin_compileError(t, decl, node, args),962 .compile_error => Builtin.builtin_compileError(t, decl, node, args),
...@@ -945,28 +970,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -945,28 +970,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
945 const args = t.ast.extraData(call.extra, Ast.Call).args.slice(&t.ast);970 const args = t.ast.extraData(call.extra, Ast.Call).args.slice(&t.ast);
946971
947 const base = try t.transformExpression(decl, call.base) orelse return null;972 const base = try t.transformExpression(decl, call.base) orelse return null;
948973 const args_list = try t.transformCallArgs(decl, args) orelse return null;
949 const args_list: RefList = brk: {
950 const args_top = t.call_args.items.len;
951 defer t.call_args.shrinkRetainingCapacity(args_top);
952
953 for (args) |arg| {
954 try t.call_args.append(
955 t.gpa,
956 try t.transformExpression(decl, arg) orelse
957 return null,
958 );
959 }
960
961 const items = t.call_args.items[args_top..];
962 const extra_top = t.extra.list.items.len;
963 try t.extra.list.appendSlice(t.gpa, @ptrCast(items));
964
965 break :brk .{
966 .start = @intCast(extra_top),
967 .len = @intCast(items.len),
968 };
969 };
970974
971 const call_inst = try t.addInstRef(.{975 const call_inst = try t.addInstRef(.{
972 .tag = .call,976 .tag = .call,
...@@ -1138,6 +1142,28 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -1138,6 +1142,28 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
1138 }1142 }
1139}1143}
11401144
1145fn transformCallArgs(t: *Transform, decl: BlockContext, args: []const NodeIndex) !?RefList {
1146 const args_top = t.call_args.items.len;
1147 defer t.call_args.shrinkRetainingCapacity(args_top);
1148
1149 for (args) |arg| {
1150 try t.call_args.append(
1151 t.gpa,
1152 try t.transformExpression(decl, arg) orelse
1153 return null,
1154 );
1155 }
1156
1157 const items = t.call_args.items[args_top..];
1158 const extra_top = t.extra.list.items.len;
1159 try t.extra.list.appendSlice(t.gpa, @ptrCast(items));
1160
1161 return .{
1162 .start = @intCast(extra_top),
1163 .len = @intCast(items.len),
1164 };
1165}
1166
1141fn transformAssignmentTarget(t: *Transform, decl: BlockContext, node: NodeIndex) Allocator.Error!?Inst.Index {1167fn transformAssignmentTarget(t: *Transform, decl: BlockContext, node: NodeIndex) Allocator.Error!?Inst.Index {
1142 const node_tag = t.ast.nodes.items(.tag)[node];1168 const node_tag = t.ast.nodes.items(.tag)[node];
11431169
src/langref/generate-langref.zig+6-1
...@@ -182,6 +182,8 @@ fn processMarkdown(gpa: std.mem.Allocator, src: []const u8, compiler_path: []con...@@ -182,6 +182,8 @@ fn processMarkdown(gpa: std.mem.Allocator, src: []const u8, compiler_path: []con
182 try writeTokenizedCode(gpa, code.items, writer);182 try writeTokenizedCode(gpa, code.items, writer);
183 try writer.writeAll("</code></pre>");183 try writer.writeAll("</code></pre>");
184184
185 try code.append('\n');
186
185 switch (tag) {187 switch (tag) {
186 .code_run,188 .code_run,
187 .code_build,189 .code_build,
...@@ -208,7 +210,8 @@ fn processMarkdown(gpa: std.mem.Allocator, src: []const u8, compiler_path: []con...@@ -208,7 +210,8 @@ fn processMarkdown(gpa: std.mem.Allocator, src: []const u8, compiler_path: []con
208 }210 }
209 if (std.mem.trim(u8, out.items, " \n\r").len > 0) {211 if (std.mem.trim(u8, out.items, " \n\r").len > 0) {
210 try writer.writeAll("<pre><code>");212 try writer.writeAll("<pre><code>");
211 try writer.writeAll(out.items);213 try writer.writeAll("// Compiled JavaScript Code");
214 try writer.writeAll(out.items[std.mem.indexOfScalar(u8, out.items, '\n').?..]);
212 try writer.writeAll("</code></pre>");215 try writer.writeAll("</code></pre>");
213 }216 }
214 },217 },
...@@ -302,6 +305,8 @@ fn processInlineMarkdown(gpa: std.mem.Allocator, src: []const u8, writer: anytyp...@@ -302,6 +305,8 @@ fn processInlineMarkdown(gpa: std.mem.Allocator, src: []const u8, writer: anytyp
302 }305 }
303}306}
304307
308// TODO: Change this to use Tree-sitter, which would also make it very simple
309// to highlight JavaScript code in addition to the language.
305fn writeTokenizedCode(gpa: std.mem.Allocator, code: []const u8, writer: anytype) !void {310fn writeTokenizedCode(gpa: std.mem.Allocator, code: []const u8, writer: anytype) !void {
306 const code_z = try gpa.dupeZ(u8, code);311 const code_z = try gpa.dupeZ(u8, code);
307 defer gpa.free(code_z);312 defer gpa.free(code_z);
src/langref/template.html+36-14
...@@ -8,7 +8,7 @@...@@ -8,7 +8,7 @@
8 * { margin: 0; padding: 0; box-sizing: border-box; }8 * { margin: 0; padding: 0; box-sizing: border-box; }
9 body {9 body {
10 background-color: #fefefe;10 background-color: #fefefe;
11 font-family: sans-serif;11 font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
12 max-width: 45rem;12 max-width: 45rem;
13 padding: 1rem;13 padding: 1rem;
14 margin: auto;14 margin: auto;
...@@ -29,44 +29,66 @@...@@ -29,44 +29,66 @@
29 padding-top: 8px;29 padding-top: 8px;
30 padding-bottom: 8px;30 padding-bottom: 8px;
31 }31 }
32 pre {
33 padding: 0.5rem;
34 }
35 pre > code {32 pre > code {
36 border: none;33 border: none;
37 padding: 0;34 padding: 0;
38 background-color: transparent;35 background-color: transparent;
39 }36 }
40 code, pre {37 code, pre {
41 border: 1px solid #999;38 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
42 background-color: #eeeeee;39 font-size: 0.9rem;
40 border: 1px solid #9ca0b0;
41 background-color: #eff1f5;
43 border-radius: 4px;42 border-radius: 4px;
44 padding: 2px 4px;43 padding: 2px 4px;
45 }44 }
45 pre {
46 padding: 0.75rem 0.75rem;
47 }
46 .term {48 .term {
47 border: 1px solid #333;49 border: 1px solid #11111b;
48 background-color: #222; 50 background-color: #24273a;
49 color:white;51 color: #cdd6f4;
50 }52 }
53
51 .ansi-1 {54 .ansi-1 {
52 font-weight: bold;55 font-weight: bold;
53 }56 }
54 .ansi-31 {57 .ansi-31 {
55 color:rgb(255, 68, 68);58 color: #ed8796;
59 }
60 .ansi-32 {
61 color: #a6e3a1;
62 }
63 .ansi-33 {
64 color: #eed49f;
65 }
66 .ansi-34 {
67 color: #8aadf4;
68 }
69 .ansi-35 {
70 color: #f5c2e7;
71 }
72 .ansi-36 {
73 color: #94e2d5;
56 }74 }
57 .ansi-2 {75 .ansi-2 {
58 color:#aaa;76 color: #8087a2;
59 }77 }
6078
61 .kw {79 .kw {
62 color: mediumpurple;80 color: #8839ef;
63 font-weight: bold;81 font-weight: bold;
64 }82 }
65 .tok-string {83 .tok-string {
66 color: green;84 color: #40a02b;
85 }
86 .tok-builtin_id {
87 color: #d20f39;
88 font-weight: bold;
67 }89 }
68 .tok-number_int, .tok-number_float {90 .tok-number_int, .tok-number_float {
69 color: orangered;91 color: #fe640b;
70 }92 }
71 </style>93 </style>
72</head>94</head>