Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.

Commit e6afcc0

Browse files
committed
compiler
1 parent c34072f commit e6afcc0

File tree

160 files changed

+16342
-2230
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

160 files changed

+16342
-2230
lines changed

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- "**"
7+
pull_request:
8+
branches:
9+
- "**"
10+
11+
jobs:
12+
build-and-test:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
19+
- name: Install dependencies
20+
run: make install
21+
shell: bash
22+
23+
- name: Add Bun to PATH
24+
run: echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
25+
shell: bash
26+
27+
- name: Run tests
28+
run: make test
29+
shell: bash
30+
31+
- name: Build project
32+
run: make build
33+
shell: bash

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

Makefile

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
1-
.PHONY: build
1+
SHELL := /bin/bash
2+
3+
ESC := \033
4+
RESET := $(ESC)[0m
5+
BOLD := $(ESC)[1m
6+
DIM := $(ESC)[2m
7+
GREEN := $(ESC)[32m
8+
YELLOW := $(ESC)[33m
9+
RED := $(ESC)[31m
10+
CYAN := $(ESC)[36m
11+
12+
.PHONY: build cli test dev start install
13+
14+
CLI_ARGS := $(filter-out build cli test dev start install,$(MAKECMDGOALS))
15+
16+
$(CLI_ARGS):
17+
@:
18+
19+
cli: $(CLI_ARGS)
20+
@test -n "$(CLI_ARGS)" || (printf "$(RED)Usage: make cli path/to/file.toy$(RESET)\n" && exit 2)
21+
@scripts/cli.sh $(CLI_ARGS)
22+
23+
test:
24+
@$(MAKE) -C compiler build $(MAKEOVERRIDES)
25+
@COMPILER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
26+
scripts/test.sh
227

328
build:
429
@$(MAKE) -C compiler build $(MAKEOVERRIDES)
5-
ANALYZER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
30+
COMPILER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
631
$(MAKE) -C frontend build $(MAKEOVERRIDES)
732

833
dev:
9-
(nodemon --watch compiler --ext cs --ignore compiler/obj \
10-
--exec "make -C compiler build && echo 'Rebuilt compiler'") & \
11-
echo "Starting frontend development server..."; \
12-
ANALYZER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
13-
$(MAKE) -C frontend dev $(MAKEOVERRIDES) -- $(ARGS) & \
14-
wait
34+
@scripts/dev.sh $(ARGS)
1535

1636
start:
17-
ANALYZER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
37+
COMPILER_PATH=$$(dirname $(abspath $(lastword $(MAKEFILE_LIST))))/compiler/bin/Release/net9.0/CompilersApp \
1838
$(MAKE) -C frontend start $(MAKEOVERRIDES) -- $(ARGS)
1939

2040
install:
21-
which bun > /dev/null || (echo "Please install bun: https://bun.sh/" && exit 1)
22-
which dotnet > /dev/null || (echo "Please install dotnet: https://dotnet.microsoft.com/en-us/download" && exit 1)
23-
cd frontend && bun install
41+
@scripts/install.sh

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Ultra Giga Compiler Pro Max 2025
2+
3+
## Prereqs
4+
5+
* .NET 9 SDK
6+
* Node 18+ + Bun
7+
* wasi-sdk/wasm-tools
8+
9+
Make sure `dotnet`, `npm`, `bun`, `nodemon` and `wasm-validate` are on your `$PATH`.
10+
11+
## Auto-tests
12+
13+
```bash
14+
make install
15+
make test
16+
```
17+
18+
## Manual tests
19+
20+
```bash
21+
make install
22+
make cli compiler/tests/donut.toy
23+
make cli compiler/tests/os.toy
24+
# ...
25+
```
26+
27+
## Starting the web UI
28+
29+
```bash
30+
make install
31+
make build
32+
make start
33+
```
34+
35+
Open http://localhost:3000 and you get the playground.
36+
37+
## Style
38+
39+
* C#: `dotnet format` with the default style.
40+
* TS/JS: prettier via `npx prettier . --fix`.

compiler/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
ARGS ?=
44

55
build:
6-
dotnet build -c Release
6+
@scripts/build.sh
77

88
run: build
99
dotnet run -- $(ARGS)

compiler/Program.cs

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Text.Json.Serialization;
44
using MiniLang.Semantic;
55
using MiniLang.Syntax;
6+
using MiniLang.Wasm;
67

78
public class Program
89
{
@@ -77,6 +78,8 @@ public static void Main(string[] args)
7778
return;
7879
}
7980

81+
var lineStarts = SourceMapping.ComputeLineStarts(sourceCode);
82+
8083
TextWriter writer = outputFile != null
8184
? new StreamWriter(outputFile, false, new UTF8Encoding(false))
8285
: Console.Out;
@@ -91,18 +94,24 @@ public static void Main(string[] args)
9194
};
9295

9396
IReadOnlyList<Token> tokens;
97+
IReadOnlyDictionary<int, List<Token>> tokensByLine;
9498
try
9599
{
96100
tokens = new Lexer(sourceCode).ScanTokens();
101+
tokensByLine = SourceMapping.BuildTokenLineMap(tokens);
97102
}
98103
catch (SyntaxError le)
99104
{
100-
var lexErr = new Diagnostic(Stage.Lex, le.Line, le.Message, Severity.Error);
101-
var output = new PipelineOutput(Array.Empty<Token>(), null, new SemanticReport(Array.Empty<Diagnostic>(), Array.Empty<Diagnostic>()), null, lexErr, null, null);
105+
var startOffset = SourceMapping.LineColumnToOffset(le.Line, le.Column, lineStarts, sourceCode);
106+
var endOffset = startOffset.HasValue ? Math.Min(startOffset.Value + 1, sourceCode.Length) : (int?)null;
107+
var lexErr = new Diagnostic(Stage.Lex, le.Line, le.Message, Severity.Error, startOffset, endOffset);
108+
var output = new PipelineOutput(Array.Empty<Token>(), null, new SemanticReport(Array.Empty<Diagnostic>(), Array.Empty<Diagnostic>()), null, lexErr, null, null, null);
102109
writer.WriteLine(JsonSerializer.Serialize(output, options));
103110
return;
104111
}
105112

113+
114+
106115
ProgramAst? ast = null;
107116
try
108117
{
@@ -111,33 +120,51 @@ public static void Main(string[] args)
111120
}
112121
catch (SyntaxError pe)
113122
{
114-
var parseErr = new Diagnostic(Stage.Parse, pe.Line, pe.Message, Severity.Error);
115-
var output = new PipelineOutput(tokens, null, new SemanticReport(Array.Empty<Diagnostic>(), Array.Empty<Diagnostic>()), null, parseErr, null, null);
123+
var startOffset = SourceMapping.LineColumnToOffset(pe.Line, pe.Column, lineStarts, sourceCode);
124+
var endOffset = startOffset.HasValue ? Math.Min(startOffset.Value + 1, sourceCode.Length) : (int?)null;
125+
var parseErr = new Diagnostic(Stage.Parse, pe.Line, pe.Message, Severity.Error, startOffset, endOffset);
126+
var output = new PipelineOutput(tokens, null, new SemanticReport(Array.Empty<Diagnostic>(), Array.Empty<Diagnostic>()), null, parseErr, null, null, null);
116127
writer.WriteLine(JsonSerializer.Serialize(output, options));
117128
return;
118129
}
119130

120131
var sema = new SemanticAnalyzer();
121-
var report = sema.Analyze(ast, sourceCode);
132+
var report = sema.Analyze(ast, sourceCode, tokens);
122133

123134
ProgramAst? optimized = null;
124135
List<Optimizer.OptimizationStep>? steps = null;
125136
string? optimizedSource = null;
126-
try
137+
string? wasmModuleBase64 = null;
138+
Diagnostic? stageError = null;
139+
var res = Optimizer.OptimizeWithReport(ast);
140+
optimized = res.Program;
141+
steps = res.Steps;
142+
optimizedSource = optimized != null ? CodePrinter.PrintProgram(optimized) : null;
143+
if (steps != null)
127144
{
128-
var res = Optimizer.OptimizeWithReport(ast);
129-
optimized = res.Program;
130-
steps = res.Steps;
131-
optimizedSource = optimized != null ? CodePrinter.PrintProgram(optimized) : null;
145+
steps = steps.Select(step =>
146+
{
147+
var hint = step.Hint ?? ExtractHint(step.Before);
148+
var resolvedLine = SourceMapping.ResolveLine(step.Line, hint, tokensByLine) ?? step.Line;
149+
var (startOffset, endOffset) = SourceMapping.ResolveSpan(resolvedLine, hint, sourceCode, lineStarts, tokensByLine);
150+
return step with { Line = resolvedLine, Start = startOffset, End = endOffset };
151+
}).ToList();
132152
}
133-
catch
153+
if (optimized != null)
134154
{
135-
optimized = null;
136-
steps = null;
137-
optimizedSource = null;
155+
try
156+
{
157+
var wasmBytes = WasmCompiler.Compile(optimized);
158+
wasmModuleBase64 = Convert.ToBase64String(wasmBytes);
159+
}
160+
catch (Exception ex)
161+
{
162+
wasmModuleBase64 = null;
163+
stageError = new Diagnostic(Stage.Optimize, 0, ex.Message, Severity.Error);
164+
}
138165
}
139166

140-
var result = new PipelineOutput(tokens, ast, report, optimized, null, steps, optimizedSource);
167+
var result = new PipelineOutput(tokens, ast, report, optimized, stageError, steps, optimizedSource, wasmModuleBase64);
141168
writer.WriteLine(JsonSerializer.Serialize(result, options));
142169
}
143170
catch (Exception e)
@@ -151,4 +178,34 @@ public static void Main(string[] args)
151178
writer.Dispose();
152179
}
153180
}
181+
182+
private static string? ExtractHint(string? before)
183+
{
184+
if (string.IsNullOrWhiteSpace(before))
185+
return null;
186+
187+
var trimmed = before.TrimStart();
188+
var newlineIndex = trimmed.IndexOfAny(new[] { '\r', '\n' });
189+
if (newlineIndex >= 0)
190+
trimmed = trimmed[..newlineIndex];
191+
192+
if (trimmed.Length == 0)
193+
return null;
194+
195+
var start = 0;
196+
while (start < trimmed.Length && !char.IsLetter(trimmed[start]) && trimmed[start] != '_')
197+
start++;
198+
199+
if (start >= trimmed.Length)
200+
return null;
201+
202+
var end = start;
203+
while (end < trimmed.Length && (char.IsLetterOrDigit(trimmed[end]) || trimmed[end] == '_'))
204+
end++;
205+
206+
if (end == start)
207+
return null;
208+
209+
return trimmed[start..end];
210+
}
154211
}

0 commit comments

Comments
 (0)