mirror of
https://github.com/sigmasternchen/sh.js
synced 2025-03-15 07:28:55 +00:00
created namespace for ast related constructors
This commit is contained in:
parent
741ff1c347
commit
333eb79820
1 changed files with 122 additions and 119 deletions
241
interpreter.js
241
interpreter.js
|
@ -4,111 +4,114 @@
|
||||||
var functions = [];
|
var functions = [];
|
||||||
var file = "[anonymous]";
|
var file = "[anonymous]";
|
||||||
|
|
||||||
|
|
||||||
function executeCommand(args, std) {
|
function executeCommand(args, std) {
|
||||||
console.log(`args: ${args}, std: ${std}`);
|
console.log(`args: ${args}, std: ${std}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function astSequence() {
|
const ast = {
|
||||||
let commands = [];
|
sequence: function() {
|
||||||
return {
|
let commands = [];
|
||||||
add: c => commands.push(c),
|
return {
|
||||||
execute: (std) => commands.forEach(c => c.execute(std)),
|
add: c => commands.push(c),
|
||||||
toString: () => "sequence {\n" + commands
|
execute: (std) => commands.forEach(c => c.execute(std)),
|
||||||
.map(c => c.toString())
|
toString: () => "sequence {\n" + commands
|
||||||
.map(s => s.split("\n"))
|
.map(c => c.toString())
|
||||||
.map(a => a.map(s => " " + s))
|
.map(s => s.split("\n"))
|
||||||
.map(a => a.join("\n"))
|
.map(a => a.map(s => " " + s))
|
||||||
.join(",\n") + "\n}",
|
.map(a => a.join("\n"))
|
||||||
}
|
.join(",\n") + "\n}",
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
function astCommand() {
|
command: function() {
|
||||||
let args = [];
|
let args = [];
|
||||||
return {
|
return {
|
||||||
add: a => args.push(a),
|
add: a => args.push(a),
|
||||||
size: a => args.length,
|
size: a => args.length,
|
||||||
execute: (std) => {
|
execute: (std) => {
|
||||||
let evaluatedArgs = args.map(a => a.evaluate());
|
let evaluatedArgs = args.map(a => a.evaluate());
|
||||||
executeCommand(evaluatedArgs, std);
|
executeCommand(evaluatedArgs, std);
|
||||||
|
},
|
||||||
|
toString: () => "command {\n" + args
|
||||||
|
.map(a => a.toString())
|
||||||
|
.map(s => s.split("\n"))
|
||||||
|
.map(a => a.map(s => " " + s))
|
||||||
|
.map(a => a.join("\n"))
|
||||||
|
.join(",\n") + "\n}",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
assignment: function(name) {
|
||||||
|
let value = ast.value.string("");
|
||||||
|
return {
|
||||||
|
setValue: v => { value = v; },
|
||||||
|
execute: (std) => {
|
||||||
|
variables[name] = value.evaluate();
|
||||||
|
},
|
||||||
|
toString: () => `assign '${name}'=\n${value.toString().split('\n').map(l => " " + l).join("\n")}`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
value: {
|
||||||
|
compound: function() {
|
||||||
|
let components = [];
|
||||||
|
const self = {
|
||||||
|
add: c => components.push(c),
|
||||||
|
evaluate: () => components.map(c => c.evaluate()).join(""),
|
||||||
|
toString: () => "compound {\n" + components
|
||||||
|
.map(a => a.toString())
|
||||||
|
.map(s => s.split("\n"))
|
||||||
|
.map(a => a.map(s => " " + s))
|
||||||
|
.map(a => a.join("\n"))
|
||||||
|
.join(",\n") + "\n}",
|
||||||
|
reduce: () => {
|
||||||
|
if (components.length == 1) {
|
||||||
|
if (components[0].reduce) {
|
||||||
|
return components[0].reduce();
|
||||||
|
} else {
|
||||||
|
return components[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return self;
|
||||||
},
|
},
|
||||||
toString: () => "command {\n" + args
|
|
||||||
.map(a => a.toString())
|
|
||||||
.map(s => s.split("\n"))
|
|
||||||
.map(a => a.map(s => " " + s))
|
|
||||||
.map(a => a.join("\n"))
|
|
||||||
.join(",\n") + "\n}",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function astAssignment(name) {
|
string: function(str) {
|
||||||
let value = astValueString("");
|
return {
|
||||||
return {
|
evaluate: () => str,
|
||||||
setValue: v => { value = v; },
|
toString: () => "'" + str + "'",
|
||||||
execute: (std) => {
|
};
|
||||||
variables[name] = value.evaluate();
|
|
||||||
},
|
},
|
||||||
toString: () => `assign '${name}'=\n${value.toString().split('\n').map(l => " " + l).join("\n")}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function astValueCompound() {
|
variable: function(name) {
|
||||||
let components = [];
|
return {
|
||||||
const self = {
|
// add support for multiple arguments in one variable
|
||||||
add: c => components.push(c),
|
evaluate: () => variables[name],
|
||||||
evaluate: () => components.map(c => c.evaluate()).join(""),
|
toString: () => `var '${name}'`,
|
||||||
toString: () => "compound {\n" + components
|
|
||||||
.map(a => a.toString())
|
|
||||||
.map(s => s.split("\n"))
|
|
||||||
.map(a => a.map(s => " " + s))
|
|
||||||
.map(a => a.join("\n"))
|
|
||||||
.join(",\n") + "\n}",
|
|
||||||
reduce: () => {
|
|
||||||
if (components.length == 1) {
|
|
||||||
if (components[0].reduce) {
|
|
||||||
return components[0].reduce();
|
|
||||||
} else {
|
|
||||||
return components[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
function astValueString(str) {
|
commandSubstitution: function(ast) {
|
||||||
return {
|
return {
|
||||||
evaluate: () => str,
|
evaluate: () => {
|
||||||
toString: () => "'" + str + "'",
|
// TODO
|
||||||
};
|
},
|
||||||
}
|
toString: () => "not implemented",
|
||||||
|
};
|
||||||
function astValueVar(name) {
|
|
||||||
return {
|
|
||||||
// add support for multiple arguments in one variable
|
|
||||||
evaluate: () => variables[name],
|
|
||||||
toString: () => `var '${name}'`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function astValueCommandSubstitution(ast) {
|
|
||||||
return {
|
|
||||||
evaluate: () => {
|
|
||||||
// TODO
|
|
||||||
},
|
},
|
||||||
toString: () => "not implemented",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function astValueProcessSubstitution(ast) {
|
processSubstitution: function(ast) {
|
||||||
return {
|
return {
|
||||||
evaluate: () => {
|
evaluate: () => {
|
||||||
// TODO
|
// TODO
|
||||||
|
},
|
||||||
|
toString: () => "not implemented",
|
||||||
|
};
|
||||||
},
|
},
|
||||||
toString: () => "not implemented",
|
},
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function panic(line, message) {
|
function panic(line, message) {
|
||||||
|
@ -172,7 +175,7 @@
|
||||||
function doubleQuoteToAst(quoteContent, line) {
|
function doubleQuoteToAst(quoteContent, line) {
|
||||||
const length = quoteContent.length;
|
const length = quoteContent.length;
|
||||||
|
|
||||||
let astRoot = astValueCompound();
|
let astRoot = ast.value.compound();
|
||||||
|
|
||||||
let buffer = "";
|
let buffer = "";
|
||||||
|
|
||||||
|
@ -189,7 +192,7 @@
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case QS_INIT:
|
case QS_INIT:
|
||||||
if (c == '$') {
|
if (c == '$') {
|
||||||
astRoot.add(astValueString(buffer));
|
astRoot.add(ast.value.string(buffer));
|
||||||
buffer = "";
|
buffer = "";
|
||||||
if (i < length - 1 && quoteContent[i + 1] == '(') {
|
if (i < length - 1 && quoteContent[i + 1] == '(') {
|
||||||
state = QS_SUBSTITUTION;
|
state = QS_SUBSTITUTION;
|
||||||
|
@ -203,7 +206,7 @@
|
||||||
break;
|
break;
|
||||||
case QS_VARIABLE:
|
case QS_VARIABLE:
|
||||||
if (!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".includes(c))) {
|
if (!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".includes(c))) {
|
||||||
astRoot.add(astValueVar(buffer));
|
astRoot.add(ast.value.variable(buffer));
|
||||||
buffer = "";
|
buffer = "";
|
||||||
state = QS_INIT;
|
state = QS_INIT;
|
||||||
i--;
|
i--;
|
||||||
|
@ -223,10 +226,10 @@
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case QS_INIT:
|
case QS_INIT:
|
||||||
astRoot.add(astValueString(buffer));
|
astRoot.add(ast.value.string(buffer));
|
||||||
break;
|
break;
|
||||||
case QS_VARIABLE:
|
case QS_VARIABLE:
|
||||||
astRoot.add(astValueVar(buffer));
|
astRoot.add(ast.value.variable(buffer));
|
||||||
break;
|
break;
|
||||||
case QS_SUBSTITUTION:
|
case QS_SUBSTITUTION:
|
||||||
throw "not implemented";
|
throw "not implemented";
|
||||||
|
@ -248,7 +251,7 @@
|
||||||
const PS_COMMAND = 1;
|
const PS_COMMAND = 1;
|
||||||
const PS_ASSIGN = 2;
|
const PS_ASSIGN = 2;
|
||||||
|
|
||||||
let astRoot = astSequence();
|
let astRoot = ast.sequence();
|
||||||
let current = null;
|
let current = null;
|
||||||
let value = null;
|
let value = null;
|
||||||
|
|
||||||
|
@ -265,7 +268,7 @@
|
||||||
} else if (c == '#') {
|
} else if (c == '#') {
|
||||||
state = PS_COMMENT;
|
state = PS_COMMENT;
|
||||||
} else {
|
} else {
|
||||||
current = astCommand();
|
current = ast.command();
|
||||||
buffer = c;
|
buffer = c;
|
||||||
state = PS_COMMAND;
|
state = PS_COMMAND;
|
||||||
}
|
}
|
||||||
|
@ -281,9 +284,9 @@
|
||||||
if (value) {
|
if (value) {
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (buffer[0] == '$') {
|
if (buffer[0] == '$') {
|
||||||
value.add(astValueVar(buffer.substring(1)));
|
value.add(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
value.add(astValueString(buffer.replaceAll('\\$', '$')));
|
value.add(ast.value.string(buffer.replaceAll('\\$', '$')));
|
||||||
}
|
}
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
|
@ -291,9 +294,9 @@
|
||||||
value = null;
|
value = null;
|
||||||
} else if (buffer) {
|
} else if (buffer) {
|
||||||
if (buffer[0] == '$') {
|
if (buffer[0] == '$') {
|
||||||
current.add(astValueVar(buffer.substring(1)));
|
current.add(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
current.add(astValueString(buffer.replaceAll('\\$', '$')));
|
current.add(ast.value.string(buffer.replaceAll('\\$', '$')));
|
||||||
}
|
}
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
|
@ -304,9 +307,9 @@
|
||||||
if (value) {
|
if (value) {
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (buffer[0] == '$') {
|
if (buffer[0] == '$') {
|
||||||
value.add(astValueVar(buffer.substring(1)));
|
value.add(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
value.add(astValueString(buffer.replaceAll('\\$', '$')));
|
value.add(ast.value.string(buffer.replaceAll('\\$', '$')));
|
||||||
}
|
}
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
|
@ -314,26 +317,26 @@
|
||||||
value = null;
|
value = null;
|
||||||
} else if (buffer) {
|
} else if (buffer) {
|
||||||
if (buffer[0] == '$') {
|
if (buffer[0] == '$') {
|
||||||
current.add(astValueVar(buffer.substring(1)));
|
current.add(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
current.add(astValueString(buffer.replaceAll('\\$', '$')));
|
current.add(ast.value.string(buffer.replaceAll('\\$', '$')));
|
||||||
}
|
}
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
} else if (c == '"') {
|
} else if (c == '"') {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
value = astValueCompound();
|
value = ast.value.compound();
|
||||||
}
|
}
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
value.add(astValueString(buffer));
|
value.add(ast.value.string(buffer));
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const end = findSymbolInScope(content, line, '"', i + 1, length);
|
const end = findSymbolInScope(content, line, '"', i + 1, length);
|
||||||
const [ast, _line] = doubleQuoteToAst(content.substring(i + 1, end), line);
|
const [_ast, _line] = doubleQuoteToAst(content.substring(i + 1, end), line);
|
||||||
line = _line;
|
line = _line;
|
||||||
|
|
||||||
value.add(ast);
|
value.add(_ast);
|
||||||
|
|
||||||
i = end;
|
i = end;
|
||||||
} else if (c == "'") {
|
} else if (c == "'") {
|
||||||
|
@ -345,7 +348,7 @@
|
||||||
}
|
}
|
||||||
i = end;
|
i = end;
|
||||||
} else if (c == '=' && current.size() == 0) {
|
} else if (c == '=' && current.size() == 0) {
|
||||||
current = astAssignment(buffer);
|
current = ast.assignment(buffer);
|
||||||
state = PS_ASSIGN;
|
state = PS_ASSIGN;
|
||||||
buffer = "";
|
buffer = "";
|
||||||
} else {
|
} else {
|
||||||
|
@ -358,21 +361,21 @@
|
||||||
if (value) {
|
if (value) {
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (buffer[0] == "$") {
|
if (buffer[0] == "$") {
|
||||||
value.add(astValueVar(buffer.substring(1)));
|
value.add(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
value.add(astValueString(buffer));
|
value.add(ast.value.string(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current.setValue(value.reduce());
|
current.setValue(value.reduce());
|
||||||
value = null;
|
value = null;
|
||||||
} else if (buffer) {
|
} else if (buffer) {
|
||||||
if (buffer[0] == "$") {
|
if (buffer[0] == "$") {
|
||||||
current.setValue(astValueVar(buffer.substring(1)));
|
current.setValue(ast.value.variable(buffer.substring(1)));
|
||||||
} else {
|
} else {
|
||||||
current.setValue(astValueString(buffer));
|
current.setValue(ast.value.string(buffer));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
current.setValue(astValueString(""));
|
current.setValue(ast.value.string(""));
|
||||||
}
|
}
|
||||||
buffer = "";
|
buffer = "";
|
||||||
astRoot.add(current);
|
astRoot.add(current);
|
||||||
|
@ -380,18 +383,18 @@
|
||||||
state = PS_INIT;
|
state = PS_INIT;
|
||||||
} else if (c == '"') {
|
} else if (c == '"') {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
value = astValueCompound();
|
value = ast.value.compound();
|
||||||
}
|
}
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
value.add(astValueString(buffer));
|
value.add(ast.value.string(buffer));
|
||||||
buffer = "";
|
buffer = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const end = findSymbolInScope(content, line, '"', i + 1, length);
|
const end = findSymbolInScope(content, line, '"', i + 1, length);
|
||||||
const [ast, _line] = doubleQuoteToAst(content.substring(i + 1, end), line);
|
const [_ast, _line] = doubleQuoteToAst(content.substring(i + 1, end), line);
|
||||||
line = _line;
|
line = _line;
|
||||||
|
|
||||||
value.add(ast);
|
value.add(_ast);
|
||||||
|
|
||||||
i = end;
|
i = end;
|
||||||
} else if (c == "'") {
|
} else if (c == "'") {
|
||||||
|
|
Loading…
Reference in a new issue