Skip to content

Commit 84ad267

Browse files
authored
Merge pull request #54 from qupa-project/staging
Version 0.1.0
2 parents 1789a64 + 51e54f0 commit 84ad267

Some content is hidden

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

45 files changed

+1426
-371
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ You can also find a few examples in `test/pre-alpha/`.
2525
| `--execute` | Executes the binary output after successful compilation |
2626
| `--version` | Prints the version of the compiler |
2727
| `--verifyOnly` | Compiles to LLVM, but does not store the results or compiles further |
28+
| `--compileOnly` | Compiles to binary, but does not execute the result |
2829
| `--opt {num}` | Runs optimisation passes over the output (any number between 0-3 inclusive) |

changelog.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
# Change Log
22

3+
## Version 0.1.0
4+
5+
## Added
6+
- [x] ``--compileOnly`` flag which compiles to a binary, but does not execute the result
7+
- [x] Primitive class implementation
8+
- [x] Delete instruction to consume values
9+
- [x] Class destructors
10+
- [x] Class clone operations
11+
- [x] String class
12+
- [x] No longer need a return statement on a void function
13+
- [x] Bitwise cast (for core development only)
14+
- [x] Elif statement
15+
- [x] Fixed inverted signedness issues on integer comparison
16+
- [x] Escaped string characters
17+
- [x] Constant Function Arguments
18+
19+
## Fixes
20+
- [x] Bug with nested structure access
21+
- [x] Composition of stats where value is undefined in all
22+
- [x] Consumption of single continuous state (when one branch of an if returns)
23+
- [x] Fixed not detecting deconstruction of values within if-statements
24+
- [x] Ability to override function in file
25+
- [x] Allowing multiple definitions of structure term
26+
27+
## Changes
28+
- [x] The ``uvc`` command now executes the result by default.
29+
- [x] No longer need a return statement for void functions
30+
31+
## Tweaks
32+
- [x] Tweaked the automated testing to reflect the new argument changes
33+
- [x] Compiler skips merging changes between a branch if the value has not been updated in either branch
34+
335
## Version 0.0.2
436

537
### Added

compiler/compile.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const os = require('os');
88
const fs = require('fs');
99
const { exec, spawn, spawnSync } = require('child_process');
1010

11-
const version = "Uniview Compiler v0.0.2";
11+
const version = "Uniview Compiler v0.1.0 Alpha";
1212
const root = path.resolve("./");
1313

1414

@@ -26,9 +26,10 @@ if (process.argv.includes("--version")) {
2626
let config = {
2727
output: "out",
2828
source: false,
29-
execute: false,
29+
execute: true,
30+
compileOnly: false,
31+
verifyOnly: false,
3032
optimisation: "0",
31-
verifyOnly: false
3233
};
3334
let index = process.argv.indexOf('-o');
3435
if (index != -1 && index > 2) {
@@ -39,6 +40,11 @@ if (process.argv.includes('--execute')) {
3940
}
4041
if (process.argv.includes('--verifyOnly')) {
4142
config.verifyOnly = true;
43+
config.execute = false;
44+
}
45+
if (process.argv.includes('--compileOnly')) {
46+
config.compileOnly = true;
47+
config.execute = false;
4248
}
4349
index = process.argv.indexOf('-s');
4450
if (index != -1) {
@@ -51,6 +57,10 @@ if (index != -1) {
5157
);
5258
}
5359

60+
if (config.execute + config.verifyOnly + config.compileOnly > 1) {
61+
console.error("Invalid arguments");
62+
process.exit(1);
63+
}
5464

5565

5666

@@ -104,6 +114,7 @@ if (config.execute && config.source !== false) {
104114
if (config.source != "llvm") {
105115
let args = project.includes
106116
.concat([
117+
["-Wno-override-module"],
107118
["--language=ir", `${config.output}.ll`],
108119
[`-O${config.optimisation}`]
109120
])

compiler/component/class.js

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
const Function = require('./function.js');
2+
const Structure = require('./struct.js');
3+
const LLVM = require('./../middle/llvm.js');
4+
5+
class Class extends Structure {
6+
constructor (ctx, ast, external = false) {
7+
super(ctx, ast, external);
8+
this.names = {};
9+
this.meta = "CLASS";
10+
}
11+
12+
parse () {
13+
this.name = this.ast.tokens[0].tokens;
14+
this.represent = "%class." + (
15+
this.external ? this.name : `${this.name}.${this.ctx.represent}`
16+
);
17+
}
18+
19+
link (stack = []) {
20+
if (stack.indexOf(this) != -1) {
21+
this.ctx.getFile().throw(
22+
`Error: Structure ${this.name} contains itself, either directly or indirectly`,
23+
this.ast.ref.start,
24+
this.ast.ref.end
25+
);
26+
return;
27+
}
28+
if (this.linked) {
29+
return;
30+
}
31+
32+
this.size = 0;
33+
for (let node of this.ast.tokens[1].tokens) {
34+
switch (node.type) {
35+
case "comment":
36+
break;
37+
case "struct_attribute":
38+
if (this.linkTerm(node, stack) == false) {
39+
return;
40+
}
41+
break;
42+
case "function":
43+
let space = new Function(this, node, false, false);
44+
45+
if (!this.names[space.name]) {
46+
this.names[space.name] = space;
47+
} else if (
48+
!this.names[space.name].merge ||
49+
!this.names[space.name].merge(space)
50+
) {
51+
let first = this.names[space.name].ref.index < space.ref.index ?
52+
this.names[space.name].ref : space.ref;
53+
let second = this.names[space.name].ref.index > space.ref.index ?
54+
this.names[space.name].ref : space.ref;
55+
56+
this.getFile().throw(
57+
`Multiple definitions of same name ${space.name}`,
58+
first, second
59+
);
60+
this.project.markError();
61+
return false;
62+
}
63+
64+
break;
65+
default:
66+
throw new Error(`Unexpected attribute ${node.type}`);
67+
}
68+
}
69+
70+
// Link all successful functions
71+
for (let name in this.names) {
72+
this.names[name].link();
73+
}
74+
75+
76+
// Ensure this class has a destructor if any child does
77+
if (!this.getDestructor()) {
78+
let found = false;
79+
let ref = null;
80+
for (let child of this.terms) {
81+
let type = child.typeRef.type;
82+
if (type instanceof Class && type.getDestructor()) {
83+
found = true;
84+
ref = child.declared;
85+
break;
86+
}
87+
}
88+
89+
if (found) {
90+
this.getFile().throw(
91+
`Error: This class contains no destrutor function, however it's attributes do`,
92+
this.ref, ref
93+
);
94+
}
95+
}
96+
97+
// Ensure this class has a clone operation if any child does
98+
let cloner = this.getCloner();
99+
if (!cloner) {
100+
let found = false;
101+
let ref = null;
102+
for (let child of this.terms) {
103+
let type = child.typeRef.type;
104+
if (type instanceof Class && type.getCloner()) {
105+
found = true;
106+
ref = child.declared;
107+
break;
108+
}
109+
}
110+
111+
if (found) {
112+
this.getFile().throw(
113+
`Error: This class contains no clone function, however at least one of it's attributes do`,
114+
this.ref, ref
115+
);
116+
}
117+
} else {
118+
if (!cloner.returnType.match(new TypeRef(0, this, false))) {
119+
this.getFile().throw(
120+
`Error: Cloning functions must return a "${this.name}" value`,
121+
this.ref, cloner.ref
122+
);
123+
}
124+
}
125+
126+
this.linked = true;
127+
}
128+
129+
getFunction (access, signature, template) {
130+
let name;
131+
if (access.length == 0) {
132+
name = "New";
133+
} else if (access.length != 1) {
134+
return null;
135+
} else {
136+
name = access[0][1];
137+
}
138+
139+
if (this.names[name]) {
140+
return this.names[name].getFunction([], signature, template);
141+
}
142+
143+
return null;
144+
}
145+
146+
getDestructor () {
147+
if (!this.names['Delete']) {
148+
return false;
149+
}
150+
151+
return this.names['Delete'].getFunction([], [new TypeRef(0, this, false)], null);
152+
}
153+
getCloner () {
154+
if (!this.names['Clone']) {
155+
return false;
156+
}
157+
158+
return this.names['Clone'].getFunction([], [new TypeRef(0, this, true)], null);
159+
}
160+
161+
cloneInstance (argument, ref) {
162+
let cloner = this.getCloner();
163+
if (cloner) {
164+
let preamble = new LLVM.Fragment();
165+
let irType = new TypeRef(0, this, false);
166+
let id = new LLVM.ID();
167+
168+
preamble.append(new LLVM.Set(
169+
new LLVM.Name(id),
170+
new LLVM.Alloc(irType.toLLVM(ref, true))
171+
));
172+
173+
let instruction = new LLVM.Argument (
174+
irType.toLLVM(ref, false, true),
175+
new LLVM.Name(id.reference())
176+
);
177+
178+
// Call the clone opperation
179+
preamble.append(new LLVM.Call(
180+
new LLVM.Type("void", 0),
181+
new LLVM.Name(cloner.represent, true, ref),
182+
[
183+
instruction,
184+
argument
185+
], ref
186+
));
187+
188+
return {
189+
preamble,
190+
instruction
191+
};
192+
} else {
193+
return super.cloneInstance(argument, ref);
194+
}
195+
}
196+
197+
198+
compile () {
199+
super.compile();
200+
201+
for (let name in this.names) {
202+
this.names[name].compile();
203+
}
204+
}
205+
206+
toLLVM () {
207+
let out = new LLVM.Fragment();
208+
out.append(super.toLLVM());
209+
210+
for (let name in this.names) {
211+
out.append(this.names[name].toLLVM());
212+
}
213+
214+
return out;
215+
}
216+
}
217+
218+
219+
const TypeRef = require('./typeRef.js');
220+
221+
module.exports = Class;

compiler/component/execution/base.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,15 @@ class ExecutionBase {
115115
return res;
116116
}
117117

118-
let access = ast.tokens[2];
119-
while (access.length > 0) {
118+
let accesses = ast.tokens[2];
119+
for (let access of accesses) {
120120
res.hasUpdated = res.hasUpdated || !read;
121-
res = res.access(access[0][1], access[0][1].ref);
121+
res = res.access(access[1].tokens, access[1].ref);
122122
if (res.error) {
123123
return res;
124124
}
125125
preamble.merge(res.preamble);
126126
res = res.variable;
127-
128-
access.splice(0, 1);
129127
}
130128

131129
return {
@@ -178,15 +176,6 @@ class ExecutionBase {
178176
template
179177
);
180178

181-
if (type === null) {
182-
return null;
183-
}
184-
185-
// Linear types are handled by address, not value
186-
if (type.type.typeSystem == "linear") {
187-
type.pointer++;
188-
}
189-
190179
return type;
191180
}
192181

@@ -223,7 +212,7 @@ class ExecutionBase {
223212

224213
sync (branches, segment, ref){
225214
return this.scope.sync(
226-
branches.map(x => [x.entryPoint, x.scope]),
215+
branches,
227216
segment,
228217
ref
229218
);

0 commit comments

Comments
 (0)