tcl-js
Version:
tcl-js is a tcl intepreter written completely in Typescript. It is meant to replicate the tcl-sh interpreter as closely as possible.
166 lines (138 loc) • 4.13 kB
text/typescript
import { TclSimple, TclVariable } from '../types';
import { Scope } from '../scope';
import * as Is from '../is';
import { Interpreter } from '../interpreter';
import { TclError } from '../tclerror';
/**
* Function to load the procs into the scope
*
* @export
* @param {Scope} scope
*/
export function Load(scope: Scope) {
/**
* while test body
*
* @see https://wiki.tcl-lang.org/page/while
*/
scope.defineProc(
'while',
async (interpreter, args, command, helpers) => {
args = <string[]>args;
let expression = args[0];
let code = args[1];
// Create a new scope
let newScope = new Scope(interpreter.getScope());
// Set the loop variable
newScope.setSetting('loop', true);
// Interpret the procedures tcl code with the new scope
let newInterpreter = new Interpreter(interpreter.getTcl(), code, newScope);
while (await helpers.solveExpression(expression)) {
// If so run the code and return the result
newInterpreter.reset();
// Run the code
await newInterpreter.run();
// Check if we should break
let checkLoop = newScope.getSetting('loop');
if (checkLoop && typeof checkLoop !== 'boolean' && checkLoop.break)
break;
// Reset the scope loop settings
newScope.setSetting('loop', true);
}
return new TclSimple('');
},
{
arguments: {
pattern: `while test body`,
textOnly: true,
amount: 2,
},
},
);
/**
* for start test next body
*
* @see https://wiki.tcl-lang.org/page/for
*/
scope.defineProc(
'for',
async (interpreter, args, command, helpers) => {
args = <string[]>args;
let [start, test, next, code] = args;
// Create a new scope
let newScope = new Scope(interpreter.getScope());
// Run the 'start' argument
let startInterpreter = new Interpreter(interpreter.getTcl(), start, newScope);
await startInterpreter.run();
// Set the loop variable
newScope.setSetting('loop', true);
// Interpret the procedures tcl code with the new scope
let newInterpreter = new Interpreter(interpreter.getTcl(), code, newScope);
let nextInterpreter = new Interpreter(interpreter.getTcl(), next, newScope);
while (await helpers.solveExpression(test)) {
// If so run the code and return the result
newInterpreter.reset();
// Run the code
await newInterpreter.run();
// Check if we should break
let checkLoop = newScope.getSetting('loop');
if (checkLoop && typeof checkLoop !== 'boolean' && checkLoop.break)
break;
// Reset the scope loop settings
newScope.setSetting('loop', true);
// Reset the interpreter for the 'next' argument
nextInterpreter.reset();
// Execute the 'next' argument
await nextInterpreter.run();
}
return new TclSimple('');
},
{
arguments: {
pattern: `for start test next body`,
textOnly: true,
amount: 4,
},
},
);
/**
* break
*
* @see https://wiki.tcl-lang.org/page/break
*/
scope.defineProc(
'break',
async (interpreter, args, command, helpers) => {
if (!interpreter.getScope().getSetting('loop'))
throw new TclError('executed break outside of loop');
interpreter.getScope().setSubSetting('loop', 'break', true);
return new TclSimple('');
},
{
arguments: {
pattern: `break`,
amount: 0,
},
},
);
/**
* continue
*
* @see https://wiki.tcl-lang.org/page/while
*/
scope.defineProc(
'continue',
async (interpreter, args, command, helpers) => {
if (!interpreter.getScope().getSetting('loop'))
throw new TclError('executed continue outside of loop');
interpreter.getScope().setSubSetting('loop', 'continue', true);
return new TclSimple('');
},
{
arguments: {
pattern: `continue`,
amount: 0,
},
},
);
}