Skip to content

Commit

Permalink
feature [casting]: Added support for casting operator ::
Browse files Browse the repository at this point in the history
This update brings support for the casting operator `::` to expressions.
It's definition is as a normal operator but is a infix defined on top
of the `class` defaults. The cast operator checks and ensures that LHS
is a class which is verified by a unique symbol passed to the class
static chain. This is stored in the Class.UID which is then re-verified
as the class is passed back. This avoids any circular dependency issues
  • Loading branch information
Vihan committed Jun 16, 2016
1 parent 902369c commit 489439b
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 50 deletions.
2 changes: 1 addition & 1 deletion bin/install
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
echo "Downloading..."
sudo npm install
npm install
echo "Installing..."
cpath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Expand Down
4 changes: 2 additions & 2 deletions bin/path
Expand Up @@ -16,10 +16,10 @@ if [ ! -d "$($rp "$cpath/../dist")" ]; then
fi

echo "Installing executable..."
sudo cp "$($rp "$cpath/../dist/cli/cheddar")" "$1/bin/"
cp "$($rp "$cpath/../dist/cli/cheddar")" "$1/bin/"
echo "Installing cheddar..."
sudo rm -rf "$1/share/cheddar"
sudo cp -r "$($rp "$cpath/../")" "$1/share/cheddar/"
cp -r "$($rp "$cpath/../")" "$1/share/cheddar/"
echo
echo "Cleaning up..."
bash "$($rp "$cpath/cleanup")" "$1/share/cheddar"
Expand Down
22 changes: 20 additions & 2 deletions src/cli/repl.es6
Expand Up @@ -8,6 +8,15 @@ import NIL from '../interpreter/core/consts/nil';
import cheddar from '../interpreter/exec';
import tokenizer from '../tokenizer/tok';

/*== ENVIORNMENT GENERATION DEPENDENCIES ==*/
// TODO Externalize this
import dep_String from '../interpreter/core/primitives/String';
import dep_Bool from '../interpreter/core/primitives/Bool';
import dep_Number from '../interpreter/core/primitives/Number';
import dep_Array from '../interpreter/core/primitives/Array';

import CheddarVariable from '../interpreter/core/env/var';

let REPL = readline.createInterface(process.stdin, process.stdout);
REPL.setPrompt('cheddar> '.yellow.bold);
REPL.prompt();
Expand All @@ -22,8 +31,13 @@ REPL.setPrompt = (prompt, length) =>
const REPL_ERROR = text => console.log("T_REPL:ERROR".red.underline.bold + " - ".dim + text);
const REPL_HEAD = text => console.log(`━━ ${text} ━━`.bold.magenta);


let GLOBAL_SCOPE = new CheddarScope();
const CONSTANT = { Writeable: false };
let GLOBAL_SCOPE = new CheddarScope(null, new Map([
["String" , new CheddarVariable(dep_String, CONSTANT)],
["Number" , new CheddarVariable(dep_Number, CONSTANT)],
["Array" , new CheddarVariable(dep_Array , CONSTANT)],
["Boolean", new CheddarVariable(dep_Bool , CONSTANT)]
]));

REPL.on('line', function(STDIN) {

Expand All @@ -49,6 +63,10 @@ REPL.on('line', function(STDIN) {
console.log(
`${Output.constructor.Cast.get('String')(Output).value}`.magenta
);
} else if (Output instanceof CheddarScope) {
console.log(`< Instance of "${Output.constructor.Name}" >`);
} else if (Output.prototype instanceof CheddarScope) {
console.log(`< Class "${Output.Name}" >`);
} else if (typeof Output === "symbol") {
console.log(Output.toString().magenta);
} else {
Expand Down
1 change: 1 addition & 0 deletions src/interpreter/core/consts/err.es6
Expand Up @@ -8,6 +8,7 @@ export default {
CANNOT_READ_PROP : Symbol('CANNOT_READ_PROP'),

CAST_FAILED : Symbol('CAST_FAILED'),
NOT_A_CLASS : Symbol('NOT_A_CLASS'),

UNLINKED_CLASS : Symbol('UNLINKED_CLASS'),
MALFORMED_TOKEN : Symbol('MALFORMED_TOKEN'),
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter/core/consts/err_msg.es6
@@ -1,7 +1,7 @@
import RuntimeError from './err';

export default new Map([
[RuntimeError.KEY_NOT_FOUND, "Attempted to access undefined key $0"],
[RuntimeError.KEY_NOT_FOUND, "Attempted to access undefined variable ($0)"],
[RuntimeError.KEY_IS_RESERVED, "Attempted to access reserved keyword $0"],

[RuntimeError.NO_OP_BEHAVIOR, "`$0` has no behavior for types `$2` and `$1`"],
Expand Down
3 changes: 2 additions & 1 deletion src/interpreter/core/env/class.es6
Expand Up @@ -35,10 +35,11 @@
import CheddarScope from './scope';
import * as CheddarError from '../consts/err';

import { DEFAULT_OP, DEFAULT_CAST } from './defaults';
import { DEFAULT_OP, DEFAULT_CAST, IS_CLASS } from './defaults';

export default class CheddarClass extends CheddarScope {
static Name = "UNDEFINED";

// Define operators. Each item in the
// hash-map, defines behavior for the
// specific token in an OperatorToken
Expand Down
16 changes: 15 additions & 1 deletion src/interpreter/core/env/defaults.es6
Expand Up @@ -5,6 +5,9 @@ import CheddarError from '../consts/err';

import HelperInit from '../../../helpers/init';

import CheddarClass from './class'; // I really hope this works >_>

export const IS_CLASS = Symbol("IS_CLASS");
export const DEFAULT_OP = new Map([

// print: Definition
Expand All @@ -24,11 +27,22 @@ export const DEFAULT_OP = new Map([
return LHS;
}],

['::', (LHS, RHS) => {
if (!LHS.prototype instanceof CheddarClass)
return CheddarError.CAST_FAILED;

let res;
if ((res = RHS.constructor.Cast.get(LHS.Name))) {
return res(RHS);
} else {
return CheddarError.NO_OP_BEHAVIOR;
}
}],

['==', (LHS, RHS) => {
return HelperInit(require("../primitives/Bool"), RHS && LHS instanceof RHS.constructor && LHS.value === RHS.value);
}]

]);


export const DEFAULT_CAST = new Map();
48 changes: 20 additions & 28 deletions src/interpreter/core/eval/eval.es6
Expand Up @@ -24,7 +24,7 @@ import {TYPE as OP_TYPE} from '../../../tokenizer/consts/ops';
// Reference tokens
import CheddarPropertyToken from '../../../tokenizer/parsers/property';
import CheddarPrimitive from '../../../tokenizer/literals/primitive';
import CheddarTypedLiteral from '../../../tokenizer/parsers/typed';
import CheddarLiteral from '../../../tokenizer/parsers/any';
import CheddarOperatorToken from '../../../tokenizer/literals/op';
import CheddarArrayToken from '../../../tokenizer/parsers/array';
import CheddarVariableToken from '../../../tokenizer/literals/var';
Expand Down Expand Up @@ -108,38 +108,29 @@ export default class CheddarEval extends CheddarCallStack {
this.put(OPERATOR);
}

} else if (Operation instanceof CheddarTypedLiteral) {
} else if (Operation instanceof CheddarLiteral) {
// If it is a token, pass tokens to the associated class constructor
TOKEN = Operation._Tokens[0]; // Get token

TOKEN = Operation.Tokens.pop(); // Get the top token (e.g. CheddarNumber)
Operation.Tokens.push(TOKEN);
// Do a lookup in the PRIMITIVE_LINKS class and get the link class
if ((OPERATOR = PRIMITIVE_LINKS.get(TOKEN.constructor.name))) {
// OPERATOR has the class to construct upon

// This means it is a cast/constructor because it has an additional arg
if (Operation.Tokens.length > 1) {
/* TODO: Implement */;
} else {
// Otherwise locate the class to link
// and the construct it
// Do a lookup in the PRIMITIVE_LINKS class and get the link class
if ((OPERATOR = PRIMITIVE_LINKS.get(TOKEN.constructor.name))) {
// OPERATOR has the class to construct upon

// Operator Construction
OPERATOR = new OPERATOR(this.Scope);

// Initialize operator class
// check if successful (true)
if ((TOKEN = OPERATOR.init(...TOKEN.Tokens)) === true) {
// place on stack
this.put( OPERATOR );
} else {
// return error
return TOKEN;
}
// Operator Construction
OPERATOR = new OPERATOR(this.Scope);

// Initialize operator class
// check if successful (true)
if ((TOKEN = OPERATOR.init(...TOKEN.Tokens)) === true) {
// place on stack
this.put( OPERATOR );
} else {
return CheddarError.UNLINKED_CLASS;
// return error
return TOKEN;
}

} else {
return CheddarError.UNLINKED_CLASS;
}
} else if (Operation instanceof CheddarPropertyToken) {
// If it's a property
Expand All @@ -162,7 +153,8 @@ export default class CheddarEval extends CheddarCallStack {
OPERATOR = this.Scope.accessor(Operation._Tokens[0]._Tokens[0]).Value;

if (OPERATOR === CheddarError.KEY_NOT_FOUND || !OPERATOR) {
return CheddarError.KEY_NOT_FOUND;
return CheddarErrorDesc.get(CheddarError.KEY_NOT_FOUND)
.replace('$0', Operation._Tokens[0]._Tokens[0]);
}
} else {
return CheddarError.MALFORMED_TOKEN;
Expand Down
6 changes: 4 additions & 2 deletions src/tokenizer/consts/ops.es6
Expand Up @@ -20,7 +20,7 @@ export const RESERVED_KEYWORDS = new Set(
export const OP = [
'!', '^', '*', '/', '%', '+', '-', '<=', '>=', '<', '>', '==', '&', '|',
'!=', '=', '+=', '-=', '*=', '/=', '^=', '%=', '&=', '|=', '<<', '>>', '<<=', '>>=',
':',
':', '::',
'@"',
'and', 'or', 'xor',
// Unary operators
Expand All @@ -32,11 +32,13 @@ export const OP = [
'floor', 'ceil', 'round',
'len', 'reverse', 'abs', 'repr',
'sign',
'print'];
'print',
'new'];

// TODO: how will the user modify this? no idea
//TODO: fix precedence
export const UNARY_PRECEDENCE = new Map([
['new', 21000],
['!', 20000],
['-', 20000],
['+', 20000],
Expand Down
3 changes: 2 additions & 1 deletion src/tokenizer/parsers/any.es6
Expand Up @@ -15,7 +15,8 @@ export default class CheddarAnyLiteral extends CheddarLexer {

if (attempt instanceof CheddarLexer) {
this.Index = attempt.Index;
return this.close(attempt);
this.Tokens = attempt;
return this.close();
} else {
return this.error(attempt);
}
Expand Down
2 changes: 1 addition & 1 deletion src/tokenizer/parsers/expr.es6
@@ -1,7 +1,7 @@
// Cheddar Expression Parser
import O from '../literals/op';
import P from './property';
import L from './typed';
import L from './any';
import F from './function';
import CheddarLexer from '../tok/lex';
import {OP, UOP, EXPR_OPEN, EXPR_CLOSE} from '../consts/ops';
Expand Down
7 changes: 0 additions & 7 deletions src/tokenizer/parsers/typed.es6
Expand Up @@ -16,11 +16,4 @@ export default class CheddarTypedLiteral extends CheddarLexer {
[CheddarAnyLiteral]
);
}
static makeparser(arg) {
let passed = new CheddarLexer();
passed.exec = function() {
return new CheddarTypedLiteral(this.Code, this.Index).exec(arg);
};
return passed;
}
}
29 changes: 26 additions & 3 deletions test/vars.cdr
@@ -1,3 +1,26 @@
var a := "b"
var b := "c";
const d := "e";
var a := 1;
var _ := 2;
var $ := 3;
var _$:= 4;
var $_:= 5;
var a_:= 6;
var $a:= 7;
var a1:= 8;

const a := 1;
const a := [1, 2, 3];

print a;
print _;
print $;
print _$;
print $_;
print a_;
print $a;
print a1;
print _+$+_$;
print [a,_,$,_$];

//@EACH
var 1a := 1;
var a = 1;

0 comments on commit 489439b

Please sign in to comment.