Permalink
Browse files

Merge branch 'master' of github.com:marcuswestin/fun

  • Loading branch information...
2 parents 6d116b3 + 6d999f1 commit c59512428e0ed19681da943199c4c1f2f2257a2c @marcuswestin committed May 1, 2012
Showing with 112 additions and 41 deletions.
  1. +8 −0 Changelog
  2. +1 −2 bin/fun
  3. +1 −1 node_modules/dom
  4. +1 −1 node_modules/std
  5. +3 −3 package.json
  6. +18 −8 src/dev-client.html
  7. +21 −6 src/dev-server.js
  8. +3 −3 src/modules/console.fun
  9. +19 −0 src/modules/uuid.fun
  10. +5 −4 src/parser.js
  11. +18 −11 src/runtime/expressions.js
  12. +10 −2 src/runtime/library.js
  13. +4 −0 test/tests/test-2-parser.js
View
@@ -1,3 +1,11 @@
+v0.3.0
++ Alias of v0.2.23
++ v0.2.23 had enough changes to warrant a big version number bump
+
+v0.2.23
++ Wooe, so many improvements I can't even list them all.
++ Awesome dev environment! Automatically sync UI with file on every save.
+
v0.2.22
+ Allow for keywords to be XML attribute names
+ Add --normalize.css=false and minify=true commandline options
View
@@ -12,8 +12,7 @@ var commandline = optimist.usage('Usage: fun [compile] path/to/app.fun [--port=8
argv = commandline.argv,
line = argv._,
compile = line[0] == 'compile',
- filenameRaw = (compile ? line[1] : line[0]),
- filename = filenameRaw && filenameRaw[0] == '/' ? filenameRaw : path.join(process.cwd(), filenameRaw)
+ filename = (compile ? line[1] : line[0])
var opts = {
'minify': argv['minify'] == 'true',
Submodule dom updated 2 files
+4 −0 Changelog
+1 −1 package.json
Submodule std updated 2 files
+3 −0 Changelog
+1 −1 package.json
View
@@ -1,7 +1,7 @@
{
"name": "fun",
"description": "A programming language for realtime web applications",
- "version": "0.2.22",
+ "version": "0.3.0",
"homepage": "https://github.com/marcuswestin/fun",
"repository": {
"type": "git",
@@ -18,8 +18,8 @@
"clean-css": "0.3.2",
"require": "0.4.9",
"socket.io": "0.9.6",
- "dom": "0.1.3",
- "std": "0.1.34",
+ "dom": "0.1.4",
+ "std": "0.1.35",
"stylus": "0.25.0",
"colors": "0.6.0-1"
},
View
@@ -4,19 +4,29 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style type="text/css">
html, body, iframe { margin:0; width:100%; height:100%; }
+ #error { display:none; color:red; margin:0 10px; }
</style>
</head><body>
<script src="/socket.io/socket.io.js"></script>
+ <pre id="error"></pre>
+ <iframe id="output" frameborder='0' style="height:100%; width:100%;"></iframe>
<script>
- var socket = io.connect('http://localhost');
+ var socket = io.connect('http://localhost'),
+ error = document.getElementById('error'),
+ outputIframe = document.getElementById('output')
+
socket.on('change', function (data) {
- var iframe = document.getElementById('output')
- var doc = iframe.contentWindow.document
- doc.open()
- doc.write(data.html)
- doc.close()
+ if (data.error) {
+ error.style.display = 'block'
+ error.innerHTML = ''
+ error.appendChild(document.createTextNode(data.error))
+ } else {
+ error.style.display = 'none'
+ var doc = outputIframe.contentWindow.document
+ doc.open()
+ doc.write(data.html)
+ doc.close()
+ }
});
</script>
-
- <iframe id="output" frameborder='0' style="height:100%; width:100%;"></iframe>
</body></html>
View
@@ -4,7 +4,8 @@ var socketIo = require('socket.io'),
curry = require('std/curry'),
fs = require('fs'),
path = require('path'),
- time = require('std/time')
+ time = require('std/time'),
+ http = require('http')
module.exports = {
compileFile: compileFile,
@@ -15,12 +16,14 @@ module.exports = {
}
function compileFile(filename, opts, callback) {
- loadCompiler().compileFile(filename, opts, callback)
+ loadCompiler().compileFile(_resolveFilename(filename), opts, callback)
}
-function listen(port, filename, opts) {
+function listen(port, filenameRaw, opts) {
if (!port) { port = 8080 }
+ var filename = _resolveFilename(filenameRaw)
+
try {
var stat = fs.statSync(filename)
} catch(e) {
@@ -51,6 +54,10 @@ function listen(port, filename, opts) {
console.log('Fun!'.magenta, 'Serving', filenameRaw.green, 'on', ('localhost:'+port).cyan, 'with these options:\n', opts)
}
+function _resolveFilename(filename) {
+ return filename[0] == '/' ? filename : path.join(process.cwd(), filename)
+}
+
function serveDevClient(req, res) {
fs.readFile(path.join(__dirname, './dev-client.html'), curry(respond, res))
}
@@ -62,7 +69,7 @@ function mountAndWatchFile(server, filename, opts) {
serverIo.sockets.on('connection', function(socket) {
console.log("Dev client connected")
loadCompiler().compileFile(filename, opts, function broadcast(err, appHtml) {
- socket.emit('change', { error:err, html:appHtml })
+ socket.emit('change', { error:errorHtml(err), html:appHtml })
})
})
@@ -72,7 +79,7 @@ function mountAndWatchFile(server, filename, opts) {
lastChange = time.now()
console.log(filename, "changed.", "Compiling and sending.")
loadCompiler().compileFile(filename, opts, function broadcast(err, appHtml) {
- serverIo.sockets.emit('change', { error:err, html:appHtml })
+ serverIo.sockets.emit('change', { error:errorHtml(err), html:appHtml })
})
})
}
@@ -97,8 +104,16 @@ function respond(res, e, content) {
function errorHtmlResponse(e) {
return ['<!doctype html>','<body>',
'<button ontouchstart="location.reload();" onclick="location.reload()">Reload</button>',
+ errorHtml(e),
+ '</body>'
+ ].join('\n')
+}
+
+function errorHtml(e) {
+ if (!e) { return null }
+ return [
'<pre>',
- e.stack ? e.stack : e.message ? e.message : e.toString ? e.toString() : e || 'Error',
+ e.stack ? e.stack : e.message ? e.message : e.toString ? e.toString() : e || 'Error',
'</pre>'
].join('\n')
}
View
@@ -2,9 +2,9 @@ console = {
log: function(a,b,c) {
<script a=a b=b c=c>
var args = []
- if (a) { args.push(a) }
- if (b) { args.push(b) }
- if (c) { args.push(c) }
+ if (a) { args.push(a.toJSON()) }
+ if (b) { args.push(b.toJSON()) }
+ if (c) { args.push(c.toJSON()) }
window.console.log.apply(console, args)
</script>
}
View
@@ -0,0 +1,19 @@
+uuid = {
+ v4:function() {
+ result = null
+ <script result=result>
+ // http://blog.snowfinch.net/post/3254029029/uuid-v4-js Public domain by Snowfinch. Thanks!
+ var uuid = "", i, random;
+ for (i = 0; i < 32; i++) {
+ random = Math.random() * 16 | 0;
+
+ if (i == 8 || i == 12 || i == 16 || i == 20) {
+ uuid += "-"
+ }
+ uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
+ }
+ fun.set(result, uuid)
+ </script>
+ return result.copy()
+ }
+}
View
@@ -317,17 +317,18 @@ var _parseMore = astGenerator(function(leftOperatorBinding) {
return { type:'UNARY_OP', operator:prefixOperator, value:_parseMore(leftOperatorBinding) }
}
+ var expression
if (peek('symbol', L_PAREN)) {
// There are no value literals with parentheseseses.
// If wee see a paren, group the inside expression.
advance('symbol', L_PAREN)
- var expression = _parseMore(0)
+ expression = _parseMore(0)
advance('symbol', R_PAREN)
- return _addTightOperators(expression)
+ expression = _addTightOperators(expression)
+ } else {
+ expression = _addTightOperators(_parseAtomicExpressions())
}
- var expression = _addTightOperators(_parseAtomicExpressions())
-
var rightOperatorToken, impliedEqualityOp
while (true) {
// All conditional comparisons require the is keyword (e.g. `foo is < 10`)
View
@@ -3,7 +3,8 @@ var proto = require('std/proto'),
map = require('std/map'),
isArray = require('std/isArray'),
bind = require('std/bind'),
- arrayToObject = require('std/arrayToObject')
+ arrayToObject = require('std/arrayToObject'),
+ copy = require('std/copy')
// All values inherit from base
///////////////////////////////
@@ -111,20 +112,26 @@ module.exports.Function = proto(constantAtomicBase,
_type:'Function',
invoke:function(args) {
var result = variable(Null)
- var yieldValue = function(value) { result.mutate('set', [fromJsValue(value)]) }
- var isFirstExecution = true
-
- args = _cleanArgs([yieldValue, isFirstExecution].concat(args), this._content)
-
- this._content.apply(this, args)
+ this._withArgs(args, this._content, function(value) {
+ result.mutate('set', [fromJsValue(value)])
+ })
return result
},
render:function(hookName, args) {
- var yieldValue = function(value) { fromJsValue(value).render(hookName) }
-
+ this._withArgs(args, this._content, function(value) {
+ fromJsValue(value).render(hookName)
+ })
+ },
+ _withArgs:function(args, content, yieldValue) {
var executeBlock = bind(this, function() {
- this._content.apply(this, args)
- args[1] = false // hack: isFirstExecution
+ if (args[1]) {
+ // hack: isFirstExecution
+ var useArgs = copy(args)
+ args[1] = false
+ content.apply(this, useArgs)
+ } else {
+ content.apply(this, args)
+ }
})
for (var i=0; i<args.length; i++) {
View
@@ -156,7 +156,7 @@ var expressions = require('./expressions'),
})
on(input, 'change', function() {
setTimeout(function() {
- fun.set(property, null, input.checked ? fun.expressions.Yes : fun.expressions.No)
+ _doSet(property, input.checked ? fun.expressions.Yes : fun.expressions.No)
})
})
} else {
@@ -168,7 +168,7 @@ var expressions = require('./expressions'),
setTimeout(function() {
var value = input.value
if (property.getContent() === value) { return }
- fun.set(property, null, fun.expressions.Text(input.value))
+ _doSet(property, fun.expressions.Text(input.value))
input.value = value
}, 0)
}
@@ -179,6 +179,14 @@ var expressions = require('./expressions'),
if (e.keyCode == 86) { update(e) } // catch paste events
})
}
+ function _doSet(property, value) {
+ if (property._type == 'dereference') {
+ var components = property.components
+ fun.dictSet(components.value, components.key, value)
+ } else {
+ fun.set(property, value)
+ }
+ }
}
/* init & export
@@ -282,6 +282,10 @@ test('dynamic dereference')
.code('foo[bar] cat[qwe.tag()]')
.expect(a.dereference(a.reference('foo'), a.reference('bar')), a.dereference(a.reference('cat'), a.invocation(a.dereference(a.reference('qwe'), 'tag'))))
+test('foo = (1) + (1)')
+ .code('foo = (1) + (1)')
+ .expect(a.declaration('foo', a.binaryOp(a.literal(1), '+', a.literal(1))))
+
/* Util
******/
function test(name) {

0 comments on commit c595124

Please sign in to comment.