symbol_table 2.0.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 72

symbol_table

Pub build status

A generic symbol table implementation in Dart, with support for scopes and constants. The symbol tables produced by this package are hierarchical (in this case, tree-shaped), and utilize basic memoization to speed up repeated lookups.

Variables

To represent a symbol, use Variable. I opted for the name Variable to avoid conflict with the Dart primitive Symbol.

var foo = new Variable<String>('foo');
var bar = new Variable<String>('bar', value: 'baz');

// Call `lock` to mark a symbol as immutable.
var shelley = new Variable<String>('foo', value: 'bar')..lock();

foo.value = 'bar';
shelley.value = 'Mary'; // Throws a StateError - constants cannot be overwritten.

foo.lock();
foo.value = 'baz'; // Also throws a StateError - Once a variable is locked, it cannot be overwritten.

Visibility

Variables are public by default, but can also be marked as private or protected. This can be helpful if you are trying to determine which symbols should be exported from a library or class.

myVariable.visibility = Visibility.protected;
myVariable.visibility = Visibility.private;

Symbol Tables

It's easy to create a basic symbol table:

var mySymbolTable = new SymbolTable<int>();
var doubles = new SymbolTable<double>(values: {
  'hydrogen': 1.0,
  'avogadro': 6.022e23
});

// Create a new variable within the scope.
doubles.create('one');
doubles.create('one', value: 1.0);
doubles.create('one', value: 1.0, constant: true);

// Set a variable within an ancestor, OR create a new variable if none exists.
doubles.assign('two', value: 2.0);

// Completely remove a variable.
doubles.remove('two');

// Find a symbol, either in this symbol table or an ancestor.
var symbol = doubles.resolve('one');

// Find OR create a symbol.
var symbol = doubles.resolveOrCreate('one');
var symbol = doubles.resolveOrCreate('one', value: 1.0);
var symbol = doubles.resolveOrCreate('one', value: 1.0, constant: true);

Exporting Symbols

Due to the tree structure of symbol tables, it is extremely easy to extract a linear list of distinct variables, with variables lower in the hierarchy superseding their parents (effectively accomplishing variable shadowing).

var allSymbols = mySymbolTable.allVariables;

We can also extract symbols which are not private. This helps us export symbols from libraries or classes.

var exportedSymbols = mySymbolTable.allPublicVariables;

It's easy to extract symbols of a given visibility:

var exportedSymbols = mySymbolTable.allVariablesWithVisibility(Visibility.protected);

Child Scopes

There are three ways to create a new symbol table:

Regular Children

This is what most interpreters need; it simply creates a symbol table with the current symbol table as its parent. The new scope can define its own symbols, which will only shadow the ancestors within the correct scope.

var child = mySymbolTable.createChild();
var child = mySymbolTable.createChild(values: {...});

Depth

Every symbol table has an associated depth attached to it, with the depth at the root being 0. When createChild is called, the resulting child has an incremented depth.

Clones

This creates a scope at the same level as the current one, with all the same variables.

var clone = mySymbolTable.clone();

Forked Scopes

If you are implementing a language with closure functions, you might consider looking into this. A forked scope is a scope identical to the current one, but instead of merely copying references to variables, the values of variables are copied into new ones.

The new scope is essentially a "frozen" version of the current one.

It is also effectively orphaned - though it is aware of its parent, the parent scope is unaware that the forked scope is a child. Thus, calls to resolve may return old variables, if a parent has called remove on a symbol.

var forked = mySymbolTable.fork();
var forked = mySymbolTable.fork(values: {...});

Creating Names

In languages with block scope, oftentimes, identifiers will collide within a global scope. To avoid this, symbol tables expose a uniqueName() method that simply attaches a numerical suffix to an input name. The name is guaranteed to never be repeated within a specific scope.

var name0 = mySymbolTable.uniqueName('foo'); // foo0
var name1 = mySymbolTable.uniqueName('foo'); // foo1
var name2 = mySymbolTable.uniqueName('foo'); // foo2

this Context

Many languages handle a sort of this context that values within a scope may optionally be resolved against. Symbol tables can easily set their context as follows:

void foo() {
  mySymbolTable.context = thisContext;
}

Resolution of the context getter functions just like a symbol; if none is set locally, then it will refer to the parent.

void bar() {
  mySymbolTable.context = thisContext;
  expect(mySymbolTable.createChild().createChild().context, thisContext);
}

2.0.0

  • Dart 2 updates.

1.0.4

  • Added context to SymbolTable.

1.0.3

  • Converted Visibility into a Comparable class.
  • Renamed add -> create, put -> assign, and allVariablesOfVisibility -> allVariablesWithVisibility.
  • Added tests for Visibility comparing, and depth.
  • Added uniqueName() to SymbolTable.
  • Fixed a typo in remove that would have prevented it from working correctly.

1.0.2

  • Added depth to SymbolTable.
  • Added symbolTable to Variable.
  • Deprecated the redundant Constant class.
  • Deprecated Variable.markAsPrivate().
  • Added the Visibility enumerator.
  • Added the field visibility to Variable.

example/main.dart

import 'package:symbol_table/symbol_table.dart';

void main() {
  var scope = new SymbolTable<int>();
  var symbol = scope.assign('three', 3);
  print(symbol.value); // 3
  symbol.visibility = Visibility.private;

  var child = scope.createChild();
  child.create('three', value: 4);

  print(child.resolve('three').value); // 4
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  symbol_table: ^2.0.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:symbol_table/symbol_table.dart';
  
Version Uploaded Documentation Archive
2.0.0 Oct 6, 2018 Go to the documentation of symbol_table 2.0.0 Download symbol_table 2.0.0 archive
1.0.4 Nov 24, 2017 Go to the documentation of symbol_table 1.0.4 Download symbol_table 1.0.4 archive
1.0.3 Nov 17, 2017 Go to the documentation of symbol_table 1.0.3 Download symbol_table 1.0.3 archive
1.0.2 Nov 17, 2017 Go to the documentation of symbol_table 1.0.2 Download symbol_table 1.0.2 archive
1.0.1 Jul 19, 2017 Go to the documentation of symbol_table 1.0.1 Download symbol_table 1.0.1 archive
1.0.0 Jul 19, 2017 Go to the documentation of symbol_table 1.0.0 Download symbol_table 1.0.0 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
44
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
72
Learn more about scoring.

We analyzed this package on Dec 5, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.7

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:symbol_table/symbol_table.dart.

Health suggestions

Format lib/src/symbol_table.dart.

Run dartfmt to format lib/src/symbol_table.dart.

Format lib/src/visibility.dart.

Run dartfmt to format lib/src/visibility.dart.

Format lib/symbol_table.dart.

Run dartfmt to format lib/symbol_table.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev <3.0.0
Dev dependencies
test ^1.0.0