Skip to content

Commit

Permalink
fix syntax-rules #43
Browse files Browse the repository at this point in the history
throw exception when invoking syntax that shadow literal identifier
  • Loading branch information
jcubic committed Sep 17, 2020
1 parent 82b9191 commit f53ffd1
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* fix parsing options in executable (fix for `alias lips="lips -q"`)
* throw exception when evaluating `(if)`
* fix `object?` and `plain-object?`
* throw exception when invoking syntax that shadow literal identifier

## 1.0.0-beta.5
### Features
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![LIPS - Scheme Based Powerful Lisp Language](https://github.com/jcubic/lips/blob/devel/assets/lips.svg?raw=true)

[![npm](https://img.shields.io/badge/npm-1.0.0%E2%80%93beta.5-blue.svg)](https://www.npmjs.com/package/@jcubic/lips)
[![travis](https://travis-ci.org/jcubic/lips.svg?branch=devel&24be1a977f7c22fe2a04d439ab1e1e8a55964395)](https://travis-ci.org/jcubic/lips)
[![travis](https://travis-ci.org/jcubic/lips.svg?branch=devel&82b9191f07e6b8bf3e6ad82841358385a11ed924)](https://travis-ci.org/jcubic/lips)
[![Coverage Status](https://coveralls.io/repos/github/jcubic/lips/badge.svg?branch=devel&2c48907438a7265935a7b21e6931008d)](https://coveralls.io/github/jcubic/lips?branch=devel)
[![Join Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jcubic/lips)
<a href="https://twitter.com/intent/tweet?text=Powerful%20Scheme%20based%20lisp%20language%20written%20in%20JavaScript.%20It%20make%20programmer%20live%20easier%20by%20better%20interaction%20with%20JS.%20Use%20full%20power%20of%20JavaScript,%20lisp%20and%20npm%20to%20create%20your%20applications.&url=https://github.com/jcubic/lips&hashtags=javascript,opensource,lisp,scheme,language,programming">
Expand Down
6 changes: 3 additions & 3 deletions bin/lips.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ function parse_options(arg, options) {
}

// -----------------------------------------------------------------------------
function run(code, interpreter, dynamic = false) {
function run(code, interpreter, dynamic = false, env = null) {
if (typeof code !== 'string') {
code = code.toString();
}
return interpreter.exec(code, dynamic).catch(function(e) {
return interpreter.exec(code, dynamic, env).catch(function(e) {
console.error(e.message);
console.error('Call (stack-trace) to see the stack');
console.error('Thrown exception is in global exception variable, use ' +
Expand Down Expand Up @@ -145,7 +145,7 @@ function boostrap(interpreter) {
}
}
var data = fs.readFileSync(path);
return run(data, interpreter).then(next);
return run(data, interpreter, false, env.parent).then(next);
}
})();
}
Expand Down
24 changes: 16 additions & 8 deletions dist/lips.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* Copyright (c) 2014-present, Facebook, Inc.
* released under MIT license
*
* build: Thu, 17 Sep 2020 09:21:02 +0000
* build: Thu, 17 Sep 2020 09:54:40 +0000
*/
(function () {
'use strict';
Expand Down Expand Up @@ -3841,7 +3841,7 @@
// :: TODO detect cycles
// ----------------------------------------------------------------------

function extract_patterns(pattern, code, symbols, ellipsis_symbol) {
function extract_patterns(pattern, code, symbols, ellipsis_symbol, scope) {
var bindings = {
'...': {
symbols: {},
Expand Down Expand Up @@ -3878,7 +3878,9 @@
}

if (pattern instanceof LSymbol && symbols.includes(pattern.valueOf())) {
return LSymbol.is(code, pattern);
var ref = scope.ref(code);
var valid_ref = typeof ref === 'undefined' || ref === global_env;
return LSymbol.is(code, pattern) && valid_ref;
} // pattern (a b (x ...)) and (x ...) match nil


Expand Down Expand Up @@ -6883,12 +6885,18 @@

Interpreter.prototype.exec = function (code) {
var dynamic = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : false;
var env = arguments.length > 2 && arguments[2] !== undefined$1 ? arguments[2] : null;
typecheck('Intepreter::exec', code, 'string', 1);
typecheck('Intepreter::exec', dynamic, 'boolean', 2); // simple solution to overwrite this variable in each interpreter
// before evaluation of user code

global_env.set('**interaction-environment**', this.env);
return exec(code, this.env, dynamic ? this.env : false);

if (env === null) {
env = this.env;
}

return exec(code, env, dynamic ? env : false);
}; // -------------------------------------------------------------------------


Expand Down Expand Up @@ -8316,7 +8324,7 @@
while (rules !== nil) {
var rule = rules.car.car;
var expr = rules.car.cdr.car;
var bindings = extract_patterns(rule, code, symbols, ellipsis);
var bindings = extract_patterns(rule, code, symbols, ellipsis, this);

if (bindings) {
/* istanbul ignore next */
Expand Down Expand Up @@ -10414,10 +10422,10 @@

var banner = function () {
// Rollup tree-shaking is removing the variable if it's normal string because
// obviously 'Thu, 17 Sep 2020 09:21:02 +0000' == '{{' + 'DATE}}'; can be removed
// obviously 'Thu, 17 Sep 2020 09:54:40 +0000' == '{{' + 'DATE}}'; can be removed
// but disablig Tree-shaking is adding lot of not used code so we use this
// hack instead
var date = LString('Thu, 17 Sep 2020 09:21:02 +0000').valueOf();
var date = LString('Thu, 17 Sep 2020 09:54:40 +0000').valueOf();

var _date = date === '{{' + 'DATE}}' ? new Date() : new Date(date);

Expand Down Expand Up @@ -10454,7 +10462,7 @@
var lips = {
version: 'DEV',
banner: banner,
date: 'Thu, 17 Sep 2020 09:21:02 +0000',
date: 'Thu, 17 Sep 2020 09:54:40 +0000',
exec: exec,
parse: parse,
tokenize: tokenize,
Expand Down
4 changes: 2 additions & 2 deletions dist/lips.min.js

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions src/lips.js
Original file line number Diff line number Diff line change
Expand Up @@ -2289,7 +2289,7 @@
// :: list of bindings from code that match the pattern
// :: TODO detect cycles
// ----------------------------------------------------------------------
function extract_patterns(pattern, code, symbols, ellipsis_symbol) {
function extract_patterns(pattern, code, symbols, ellipsis_symbol, scope) {
var bindings = {
'...': {
symbols: { }, // symbols ellipsis (x ...)
Expand Down Expand Up @@ -2318,7 +2318,9 @@
}
if (pattern instanceof LSymbol &&
symbols.includes(pattern.valueOf())) {
return LSymbol.is(code, pattern);
const ref = scope.ref(code);
const valid_ref = typeof ref === 'undefined' || ref === global_env;
return LSymbol.is(code, pattern) && valid_ref;
}
// pattern (a b (x ...)) and (x ...) match nil
if (pattern instanceof Pair &&
Expand Down Expand Up @@ -4619,13 +4621,16 @@
this.env = user_env.inherit(name, obj);
}
// -------------------------------------------------------------------------
Interpreter.prototype.exec = function(code, dynamic = false) {
Interpreter.prototype.exec = function(code, dynamic = false, env = null) {
typecheck('Intepreter::exec', code, 'string', 1);
typecheck('Intepreter::exec', dynamic, 'boolean', 2);
// simple solution to overwrite this variable in each interpreter
// before evaluation of user code
global_env.set('**interaction-environment**', this.env);
return exec(code, this.env, dynamic ? this.env : false);
if (env === null) {
env = this.env;
}
return exec(code, env, dynamic ? env : false);
};
// -------------------------------------------------------------------------
Interpreter.prototype.get = function(value) {
Expand Down Expand Up @@ -5854,7 +5859,7 @@
while (rules !== nil) {
var rule = rules.car.car;
var expr = rules.car.cdr.car;
var bindings = extract_patterns(rule, code, symbols, ellipsis);
var bindings = extract_patterns(rule, code, symbols, ellipsis, this);
if (bindings) {
/* istanbul ignore next */
if (user_env.get('DEBUG', { throwError: false })) {
Expand Down
19 changes: 14 additions & 5 deletions tests/syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,10 @@
((_ ((a ==> b) ...) . body)
(let ((a b) ...) . body))))

(t.is (let ((==> (lambda (x) (* x x))))
(let+ ((a ==> 1)
(b ==> 2))
(==> (+ a b))))
9)))
(t.is (let+ ((a ==> 1)
(b ==> 2))
(+ a b))
3)))

(test "syntax-rules: basic ellipsis (srfi-46)"
(lambda (t)
Expand Down Expand Up @@ -655,3 +654,13 @@
(+ x y))
22)))

(test "syntax: scope + symbols"
(lambda (t)

(define-syntax foo
(syntax-rules (++)
((_ x ++ y)
(list x 1 1 y))))

(t.is (foo 1 ++ 2) (list 1 1 1 2))
(t.is (to.throw (let ((++ 10)) (foo 1 ++ 2))) true)))

0 comments on commit f53ffd1

Please sign in to comment.