Skip to content

Commit

Permalink
feature(semantic): implement chaining symbols tables in different sco…
Browse files Browse the repository at this point in the history
…pe levels
  • Loading branch information
ghaiklor committed Jul 14, 2017
1 parent 676abea commit 4791ce1
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 12 deletions.
9 changes: 5 additions & 4 deletions src/semantic/SemanticAnalyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ class SemanticAnalyzer {
* @param {Program} node
*/
onProgram(node) {
this.scope = SymbolTable.create('global', 1);
this.scope = SymbolTable.create('global', 1, this.scope);
this.visit(node.getBlock());
this.scope = this.scope.enclosingScope;
}

/**
Expand All @@ -51,8 +52,7 @@ class SemanticAnalyzer {
const procedureSymbol = ProcedureSymbol.create(procedureName);

this.scope.define(procedureSymbol);

this.scope = SymbolTable.create(procedureName, 2);
this.scope = SymbolTable.create(procedureName, this.scope.scopeLevel + 1, this.scope);

node.getParams().forEach(param => {
const paramType = this.scope.lookup(param.getType().getValue());
Expand All @@ -64,6 +64,7 @@ class SemanticAnalyzer {
});

this.visit(node.getBlock());
this.scope = this.scope.enclosingScope;
}

/**
Expand Down Expand Up @@ -96,7 +97,7 @@ class SemanticAnalyzer {
const varName = node.getVariable().getName();
const varSymbol = VariableSymbol.create(varName, typeSymbol);

if (this.scope.lookup(varName)) throw new Error(`Duplicate declaration of ${varName}`);
if (this.scope.lookup(varName, true)) throw new Error(`Duplicate declaration of ${varName}`);

this.scope.define(varSymbol);
}
Expand Down
18 changes: 13 additions & 5 deletions src/symbols/SymbolTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ class SymbolTable {
*
* @param {String} scopeName
* @param {Number} scopeLevel
* @param {SymbolTable} [enclosingScope=null]
* @example
* const table = SymbolTable.create();
* const symbol = VariableSymbol.create();
*
* table.define(symbol);
*/
constructor(scopeName, scopeLevel) {
constructor(scopeName, scopeLevel, enclosingScope = null) {
this.symbols = new Map();
this.scopeName = scopeName;
this.scopeLevel = scopeLevel;
this.enclosingScope = enclosingScope;

this.initBuiltin();
}
Expand Down Expand Up @@ -55,10 +57,15 @@ class SymbolTable {
* Lookup for a symbol in symbol table by its name.
*
* @param {String} name
* @param {Boolean} [currentScopeOnly=false]
* @returns {Symbol}
*/
lookup(name) {
return this.symbols.get(name);
lookup(name, currentScopeOnly = false) {
const symbol = this.symbols.get(name);

if (symbol) return symbol;
if (currentScopeOnly) return null;
if (this.enclosingScope) return this.enclosingScope.lookup(name);
}

/**
Expand All @@ -82,10 +89,11 @@ class SymbolTable {
* @static
* @param {String} scopeName
* @param {Number} scopeLevel
* @param {SymbolTable} [enclosingScope=null]
* @returns {SymbolTable}
*/
static create(scopeName, scopeLevel) {
return new this(scopeName, scopeLevel);
static create(scopeName, scopeLevel, enclosingScope) {
return new this(scopeName, scopeLevel, enclosingScope);
}
}

Expand Down
10 changes: 7 additions & 3 deletions test/semantic/SemanticAnalyzer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('Semantic::SemanticAnalyzer', () => {
assert.throws(() => analyzer.visit(ast), Error, 'Duplicate declaration of x');
});

it('Should properly create two symbol tables', () => {
it('Should properly traverse an AST and create/remove symbol tables', () => {
const program = `
PROGRAM main;
VAR x, y: REAL;
Expand All @@ -41,6 +41,11 @@ describe('Semantic::SemanticAnalyzer', () => {
VAR y: INTEGER;
BEGIN
END;
PROCEDURE Beta(a: INTEGER);
VAR y: REAL;
BEGIN
END;
BEGIN
END.
Expand All @@ -51,7 +56,6 @@ describe('Semantic::SemanticAnalyzer', () => {

analyzer.visit(ast);

assert.equal(analyzer.scope.scopeLevel, 2);
assert.equal(analyzer.scope.scopeName, 'Alpha');
assert.isNull(analyzer.scope);
});
});
1 change: 1 addition & 0 deletions test/symbols/SymbolTable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('Symbols::SymbolTable', () => {
assert.instanceOf(table.symbols.get('REAL'), TypeSymbol);
assert.equal(table.scopeName, 'global');
assert.equal(table.scopeLevel, 1);
assert.isNull(table.enclosingScope);
});

it('Should properly define a symbol', () => {
Expand Down

0 comments on commit 4791ce1

Please sign in to comment.