Skip to content

Commit 4be46c0

Browse files
committed
change ast and compiler to use expressions instead of string values
1 parent 89a6076 commit 4be46c0

File tree

3 files changed

+33
-33
lines changed

3 files changed

+33
-33
lines changed

src/ast.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const caf = {
1010
.filter(r => statementIsA(r, NodeType.Keyword))
1111
.map(r => r as KeywordStatement)
1212
.map(r => r.word)
13-
.sort(a => levenshtein(keyword, a));
13+
.sort(a => levenshtein(keyword, a.value));
1414

1515
return existingKeywords.map(word => {
1616
return {
@@ -20,7 +20,7 @@ const caf = {
2020
changes: {
2121
[filePath]: [{
2222
range: subRange(range),
23-
newText: word
23+
newText: word.value
2424
}]
2525
}
2626
}
@@ -44,7 +44,7 @@ export namespace syxparser {
4444
if (!statementIsA(ex, NodeType.String)) throw new CompilerError(ex.range, 'Expected file path after import statement.', filePath);
4545
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected ';' after import statement, found '${at().value}'.`, filePath);
4646
tokens.shift();
47-
return node({ type: NodeType.Import, path: ex.value, range: combineTwo(token, ex.range), modifiers: [] }, put);
47+
return node({ type: NodeType.Import, path: ex, range: combineTwo(token, ex.range), modifiers: [] }, put);
4848
}
4949

5050
/**
@@ -65,15 +65,15 @@ export namespace syxparser {
6565

6666
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected semicolon after rule statement, found '${at().value}'.`, filePath);
6767
tokens.shift();
68-
return node({ type: NodeType.Rule, rule: ruleExpr.value, value: boolEx.value, range: combineTwo(token, boolEx.range), modifiers: [] }, put);
68+
return node({ type: NodeType.Rule, rule: ruleExpr, value: boolEx.value, range: combineTwo(token, boolEx.range), modifiers: [] }, put);
6969
} else if (rule.type === 'keyword') {
7070
const keyEx = parseExpression(false, false, true);
7171
if (!statementIsA(keyEx, NodeType.String)) throw new CompilerError(keyEx.range, 'Excepted keyword.', filePath);
72-
if (!program.body.some(s => statementIsA(s, NodeType.Keyword) && s.word === keyEx.value)) throw new CompilerError(keyEx.range, `Can't find keyword '${keyEx.value}'.`, filePath, caf.mk(keyEx.value, program, keyEx.range, filePath));
72+
if (!program.body.some(s => statementIsA(s, NodeType.Keyword) && s.word.value === keyEx.value)) throw new CompilerError(keyEx.range, `Can't find keyword '${keyEx.value}'.`, filePath, caf.mk(keyEx.value, program, keyEx.range, filePath));
7373

7474
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected semicolon after rule statement, found ${at().value}.`, filePath);
7575
tokens.shift();
76-
return node({ type: NodeType.Rule, rule: ruleExpr.value, value: keyEx.value, range: combineTwo(token, keyEx.range), modifiers: [] }, put);
76+
return node({ type: NodeType.Rule, rule: ruleExpr, value: keyEx.value, range: combineTwo(token, keyEx.range), modifiers: [] }, put);
7777
}
7878
}
7979

@@ -83,12 +83,12 @@ export namespace syxparser {
8383
*/
8484
export function parseKeywordStatement(put: boolean, token: Token): Node {
8585
const ex = parseExpression(false, false, true);
86-
if (!statementIsA(ex, NodeType.String)) throw new CompilerError(ex.range, 'Expected identifier after keyword statement.', filePath);
86+
if (!statementIsA(ex, NodeType.Identifier)) throw new CompilerError(ex.range, 'Expected identifier after keyword statement.', filePath);
8787

8888
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected ';' after statement, found '${at().value}'.`, filePath);
8989
tokens.shift(); // skip semicolon
9090

91-
return node({ type: NodeType.Keyword, word: ex.value, range: combineTwo(token, ex.range), modifiers: [] }, put);
91+
return node({ type: NodeType.Keyword, word: ex, range: combineTwo(token, ex.range), modifiers: [] }, put);
9292
}
9393

9494
/**
@@ -107,16 +107,16 @@ export namespace syxparser {
107107
* @returns Parsed node.
108108
*/
109109
export function parseFunctionStatement(token: Token, put: boolean): Node {
110-
const statement: FunctionStatement = { type: NodeType.Function, arguments: [], name: '', body: [], range: defaultRange, modifiers: [] };
110+
const statement: FunctionStatement = { type: NodeType.Function, arguments: [], name: {type:NodeType.Identifier,modifiers:[],value:'',range:defaultRange}, body: [], range: defaultRange, modifiers: [] };
111111

112112
if (at().type !== TokenType.Identifier) throw new CompilerError(at().range, `Expected identifier after function statement, found '${at().value}'.`, filePath);
113-
statement.name = at().value;
113+
statement.name = {type:NodeType.Identifier,modifiers:[],range:at().range,value:at().value};
114114
tokens.shift();
115115

116116
while (at().type !== TokenType.OpenBrace) {
117117
const expr = parseExpression(false, false) as Expression;
118118
if (!statementIsA(expr, NodeType.PrimitiveType)) throw new CompilerError(expr.range, `Expected argument types after function name, found ${expr.value}.`, filePath);
119-
statement.arguments.push(expr.value);
119+
statement.arguments.push(expr);
120120
}
121121

122122
const braceExpr = parseExpression(false);
@@ -134,7 +134,7 @@ export namespace syxparser {
134134
* @returns Parsed node.
135135
*/
136136
export function parseImportsStatement(token: Token, put: boolean) {
137-
const statement: ImportsStatement = { type: NodeType.Imports, formats: [], module: '', range: defaultRange, modifiers: [] };
137+
const statement: ImportsStatement = { type: NodeType.Imports, formats: [], module: {type:NodeType.String,modifiers:[],range:defaultRange,value:''}, range: defaultRange, modifiers: [] };
138138

139139
if (at().type !== TokenType.OpenParen) throw new CompilerError(at().range, 'Imports statement require parens.', filePath);
140140

@@ -145,7 +145,7 @@ export namespace syxparser {
145145
if (t.type === TokenType.Comma && at().type !== TokenType.Identifier) throw new CompilerError(t.range, 'Expected identifier after comma.', filePath);
146146
else if (t.type === TokenType.Comma && statement.formats.length === 0) throw new CompilerError(t.range, 'Can\'t start with comma.', filePath);
147147
else if (t.type === TokenType.Comma) { }
148-
else if (t.type === TokenType.Identifier) statement.formats.push(t.value);
148+
else if (t.type === TokenType.Identifier) statement.formats.push({type:NodeType.Identifier,modifiers:[],range:t.range,value:t.value});
149149
else throw new CompilerError(t.range, `Expected comma or identifier, found '${t.value}'.`, filePath);
150150
}
151151
tokens.shift(); // skip CloseParen
@@ -157,7 +157,7 @@ export namespace syxparser {
157157

158158
if (!statementIsA(moduleExpr, NodeType.String)) throw new CompilerError(moduleExpr.range, `Expected string after parens of imports statement, found '${moduleExpr.value}'.`, filePath);
159159

160-
statement.module = moduleExpr.value;
160+
statement.module = moduleExpr;
161161
statement.range = combineTwo(token, moduleExpr.range);
162162

163163
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected ';' after imports statement, found '${at().value}'.`, filePath);
@@ -182,7 +182,7 @@ export namespace syxparser {
182182
if (t.type === TokenType.Comma && at().type !== TokenType.Identifier) throw new CompilerError(t.range, 'Expected identifier after comma.', filePath);
183183
else if (t.type === TokenType.Comma && statement.formats.length === 0) throw new CompilerError(t.range, 'Can\'t start with comma.', filePath);
184184
else if (t.type === TokenType.Comma) { }
185-
else if (t.type === TokenType.Identifier) statement.formats.push(t.value);
185+
else if (t.type === TokenType.Identifier) statement.formats.push({type:NodeType.Identifier,modifiers:[],range:t.range,value:t.value});
186186
else throw new CompilerError(t.range, `Expected comma or identifier, found '${t.value}'.`, filePath);
187187
}
188188
tokens.shift(); // skip CloseParen
@@ -227,10 +227,11 @@ export namespace syxparser {
227227
* @returns Parsed node.
228228
*/
229229
export function parseGlobalStatement(token: Token, put: boolean) {
230-
const stmt: GlobalStatement = { type: NodeType.Global, range: token.range, body: [], modifiers: [], name: '' };
230+
const stmt: GlobalStatement = { type: NodeType.Global, range: token.range, body: [], modifiers: [], name: {type:NodeType.Identifier,modifiers:[],range:defaultRange,value:''} };
231231

232232
if (at().type !== TokenType.Identifier) throw new CompilerError(at().range, `Expected identifier after function statement, found '${at().value}'.`, filePath);
233-
stmt.name = tokens.shift().value;
233+
const {range,value} = tokens.shift();
234+
stmt.name = {modifiers:[],type:NodeType.Identifier,range,value};
234235

235236
const braceExpr = parseExpression(false, false, false);
236237
if (!statementIsA(braceExpr, NodeType.Brace)) throw new CompilerError(braceExpr.range, 'Expected braces after global name.', filePath);
@@ -493,7 +494,7 @@ export namespace syxparser {
493494
* @param {boolean} expectIdentifier Whether identifiers should be allowed. Unknown identifiers will stop the function with this value set to `false`, returning the identifier as a {@link StringExpression} otherwise.
494495
* @returns The parsed node.
495496
* @author efekos
496-
* @version 1.0.9
497+
* @version 1.1.0
497498
* @since 0.0.2-alpha
498499
*/
499500
export function parseExpression(put: boolean = true, statements: boolean = true, expectIdentifier: boolean = false): Node {
@@ -514,7 +515,7 @@ export namespace syxparser {
514515
return parseStatement();
515516
} else if (expectIdentifier) {
516517
const { value, range } = tokens.shift();
517-
return node({ type: NodeType.String, value, range, modifiers: [] }, put);
518+
return node({ type: NodeType.Identifier, value, range, modifiers: [] }, put);
518519
}
519520
}
520521

@@ -546,7 +547,7 @@ export namespace sysparser {
546547
if (!statementIsA(ex, NodeType.String)) throw new CompilerError(ex.range, 'Expected file path after import statement.', filePath);
547548
if (at().type !== TokenType.Semicolon) throw new CompilerError(at().range, `Expected ';' after import statement, found '${at().value}'.`, filePath);
548549
tokens.shift();
549-
return node({ type: NodeType.Import, path: (ex as Expression).value, range: combineTwo(token, ex.range), modifiers: [] }, put);
550+
return node({ type: NodeType.Import, path: ex, range: combineTwo(token, ex.range), modifiers: [] }, put);
550551
}
551552

552553
//#

src/compiler.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class SyntaxScriptCompiler {
6565
* Compiles one .syx file from the path given.
6666
* @param {string} file Path to a file to compile.
6767
* @author efekos
68-
* @version 1.0.5
68+
* @version 1.0.6
6969
* @since 0.0.2-alpha
7070
*/
7171
public compileSyx(file: string) {
@@ -90,9 +90,9 @@ export class SyntaxScriptCompiler {
9090
const compileStmt = stmt as CompileStatement;
9191

9292
compileStmt.formats.forEach(frmt => {
93-
if (operatorStmtExport.outputGenerators[frmt] !== undefined) throw new CompilerError(compileStmt.range, `Duplicate file format at compile statement \'${frmt}\'`);
93+
if (operatorStmtExport.outputGenerators[frmt.value] !== undefined) throw new CompilerError(compileStmt.range, `Duplicate file format at compile statement \'${frmt}\'`);
9494

95-
operatorStmtExport.outputGenerators[frmt] = (src) => {
95+
operatorStmtExport.outputGenerators[frmt.value] = (src) => {
9696
let out = '';
9797

9898
compileStmt.body.forEach(e => {
@@ -115,29 +115,29 @@ export class SyntaxScriptCompiler {
115115
const importStmt = stmt as ImportsStatement;
116116

117117
importStmt.formats.forEach(frmt => {
118-
if (operatorStmtExport.imports[frmt] !== undefined) throw new CompilerError(importStmt.range, `Duplicate file format at imports statement \'${frmt}\'`);
119-
operatorStmtExport.imports[frmt] = importStmt.module;
118+
if (operatorStmtExport.imports[frmt.value] !== undefined) throw new CompilerError(importStmt.range, `Duplicate file format at imports statement \'${frmt}\'`);
119+
operatorStmtExport.imports[frmt.value] = importStmt.module.value;
120120
});
121121

122122
} else throw new CompilerError(stmt.range, `Unexpected \'${stmt.type}\' statement insdie operator statement.`);
123123
});
124124

125125
out.push(operatorStmtExport);
126126
} else if (statementIsA(statement, NodeType.Function)) {
127-
const statementExport: ExportedFunction = { type: ExportType.Function, args: statement.arguments.map(s => regexes[s]), name: statement.name, formatNames: {}, imports: {} };
127+
const statementExport: ExportedFunction = { type: ExportType.Function, args: statement.arguments.map(s => regexes[s.value]), name: statement.name.value, formatNames: {}, imports: {} };
128128

129129
statement.body.forEach(stmt => {
130130

131131
if (statementIsA(stmt, NodeType.Compile)) {
132132
if (stmt.body[0].type !== NodeType.String) throw new CompilerError(stmt.range, 'Expected a string after compile statement parens');
133133
stmt.formats.forEach(each => {
134-
if (statementExport.formatNames[each] !== undefined) throw new CompilerError(stmt.range, `Encountered multiple compile statements for target language '${each}'`);
135-
statementExport.formatNames[each] = stmt.body[0].value;
134+
if (statementExport.formatNames[each.value] !== undefined) throw new CompilerError(stmt.range, `Encountered multiple compile statements for target language '${each}'`);
135+
statementExport.formatNames[each.value] = stmt.body[0].value;
136136
});
137137
} else if (statementIsA(stmt, NodeType.Imports)) {
138138
stmt.formats.forEach(each => {
139-
if (statementExport.imports[each] !== undefined) throw new CompilerError(stmt.range, `Encountered multiple import statements for target language '${each}'`);
140-
statementExport.imports[each] = stmt.module;
139+
if (statementExport.imports[each.value] !== undefined) throw new CompilerError(stmt.range, `Encountered multiple import statements for target language '${each}'`);
140+
statementExport.imports[each.value] = stmt.module.value;
141141
});
142142
}
143143

@@ -146,7 +146,7 @@ export class SyntaxScriptCompiler {
146146

147147
out.push(statementExport);
148148
} else if (statementIsA(statement, NodeType.Keyword)) {
149-
out.push({ type: ExportType.Keyword, word: statement.word });
149+
out.push({ type: ExportType.Keyword, word: statement.word.value });
150150
} else if (statementIsA(statement, NodeType.Global)) {
151151
//TODO
152152
} else throw new CompilerError(statement.range, `Unexpected \'${statement.type}\' statement after export statement.`, file);
@@ -189,7 +189,7 @@ export class SyntaxScriptCompiler {
189189
if (stmt.type === NodeType.Import) {
190190
const importStmt = stmt as ImportStatement;
191191

192-
const pathToImport = join(dirname(file), importStmt.path.endsWith('.syx') ? importStmt.path : importStmt.path + '.syx');
192+
const pathToImport = join(dirname(file), importStmt.path.value.endsWith('.syx') ? importStmt.path.value : importStmt.path.value + '.syx');
193193
if (!existsSync(pathToImport)) throw new CompilerError(importStmt.range, `File \'${pathToImport}\' imported from \'${file}\' does not exist.`);
194194
this.exportData[pathToImport].forEach(exported => {
195195
if (exported.type === ExportType.Operator)

src/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,6 @@ export interface StringExpression extends Expression {
354354
*/
355355
export interface IdentifierExpression extends Expression {
356356
type: NodeType.Identifier;
357-
name: string;
358357
}
359358

360359
/**

0 commit comments

Comments
 (0)