Still needs work

This commit is contained in:
Tobe O 2017-09-30 19:01:30 -04:00
parent 2056d1eacc
commit cec21c0e7d
16 changed files with 205 additions and 14 deletions

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="main.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
<option name="filePath" value="$PROJECT_DIR$/angel_jael/example/main.dart" />
<option name="workingDirectory" value="$PROJECT_DIR$/angel_jael/example" />
<method />
</configuration>
</component>

View file

@ -0,0 +1,27 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_jael/angel_jael.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
main() async {
var app = new Angel();
var fileSystem = const LocalFileSystem();
await app.configure(
jael(fileSystem.directory('views')),
);
app.get('/', (res) => res.render('index', {'title': 'ESKETTIT'}));
app.use(() => throw new AngelHttpException.notFound());
app.logger = new Logger('angel')
..onRecord.listen((rec) {
print(rec);
if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace);
});
var server = await app.startServer(null, 3000);
print('Listening at http://${server.address.address}:${server.port}');
}

View file

@ -0,0 +1,5 @@
<extend src="layout.jl">
<block name="content">
Hello, world!!!
</block>
</extend>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>
{{title}}
</h1>
<block name="content">
<i>Content goes here.</i>
</block>
<script>
window.alert("a");
</script>
</body>
</html>

View file

@ -0,0 +1,87 @@
import 'dart:convert';
import 'package:angel_framework/angel_framework.dart';
import 'package:code_buffer/code_buffer.dart';
import 'package:file/file.dart';
import 'package:jael/jael.dart';
import 'package:jael_preprocessor/jael_preprocessor.dart';
import 'package:symbol_table/symbol_table.dart';
AngelConfigurer jael(Directory viewsDirectory,
{String fileExtension, CodeBuffer createBuffer()}) {
fileExtension ??= '.jl';
createBuffer ??= () => new CodeBuffer();
return (Angel app) async {
app.viewGenerator = (String name, [Map locals]) async {
var file = viewsDirectory.childFile(name + fileExtension);
var contents = await file.readAsString();
var errors = <JaelError>[];
var doc =
parseDocument(contents, sourceUrl: file.uri, onError: errors.add);
var processed = doc;
try {
processed = await resolve(doc, viewsDirectory, onError: errors.add);
} catch (_) {
// Ignore these errors, so that we can show syntax errors.
}
var buf = createBuffer();
var scope = new SymbolTable(values: locals ?? {});
if (errors.isEmpty) {
try {
const Renderer().render(processed, buf, scope);
return buf.toString();
} on JaelError catch (e) {
errors.add(e);
}
}
buf
..writeln('<!DOCTYPE html>')
..writeln('<html lang="en">')
..indent()
..writeln('<head>')
..indent()
..writeln(
'<meta name="viewport" content="width=device-width, initial-scale=1">',
)
..writeln('<title>${errors.length} Error(s)</title>')
..outdent()
..writeln('</head>')
..writeln('<body>')
..writeln('<h1>${errors.length} Error(s)</h1>')
..writeln('<ul>')
..indent();
for (var error in errors) {
var type =
error.severity == JaelErrorSeverity.warning ? 'warning' : 'error';
buf
..writeln('<li>')
..indent()
..writeln(
'<b>$type:</b> ${error.span.start.toolString}: ${error.message}')
..writeln('<br>')
..writeln(
'<span style="color: red;">' +
HTML_ESCAPE
.convert(error.span.highlight(color: false))
.replaceAll('\n', '<br>') +
'</span>',
)
..outdent()
..writeln('</li>');
}
buf
..outdent()
..writeln('</ul>')
..writeln('</body>')
..writeln('</html>');
return buf.toString();
};
};
}

16
angel_jael/pubspec.yaml Normal file
View file

@ -0,0 +1,16 @@
name: angel_jael
dependencies:
angel_framework: ^1.0.0-dev
code_buffer: ^1.0.0
file: ^2.0.0
jael: ^1.0.0-alpha
jael_preprocessor: ^1.0.0-alpha
symbol_table: ^1.0.0
dev_dependencies:
angel_test: ^1.1.0-alpha
test: ^0.12.0
dependency_overrides:
jael:
path: ../jael
jael_preprocessor:
path: ../jael_preprocessor

View file

@ -2,7 +2,10 @@
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/angel_jael" />
<content url="file://$MODULE_DIR$/angel_jael">
<excludeFolder url="file://$MODULE_DIR$/angel_jael/.pub" />
<excludeFolder url="file://$MODULE_DIR$/angel_jael/build" />
</content>
<content url="file://$MODULE_DIR$/jael">
<excludeFolder url="file://$MODULE_DIR$/jael/.pub" />
<excludeFolder url="file://$MODULE_DIR$/jael/build" />

View file

@ -38,7 +38,7 @@ class BinaryExpression extends Expression {
return l ?? r;
default:
throw new UnsupportedError(
'Unsupported binary operator: "${operator?.span ?? "<null>"}".');
'Unsupported binary operator: "${operator?.span?.text ?? "<null>"}".');
}
}

View file

@ -10,10 +10,22 @@ class Identifier extends Expression {
@override
compute(SymbolTable scope) {
var symbol = scope.resolve(name);
if (symbol == null)
throw new ArgumentError('The name "$name" does not exist in this scope.');
return scope.resolve(name).value;
switch(name) {
case 'null':
return null;
case 'true':
return true;
case 'false':
return false;
default:
var symbol = scope.resolve(name);
if (symbol == null)
throw new ArgumentError(
'The name "$name" does not exist in this scope.');
return scope
.resolve(name)
.value;
}
}
String get name => id.span.text;

View file

@ -7,17 +7,18 @@ import 'token.dart';
class MemberExpression extends Expression {
final Expression expression;
final Token dot;
final Token op;
final Identifier name;
MemberExpression(this.expression, this.dot, this.name);
MemberExpression(this.expression, this.op, this.name);
@override
compute(SymbolTable scope) {
var target = expression.compute(scope);
if (op.span.text == '?.' && target == null) return null;
return reflect(target).getField(new Symbol(name.name)).reflectee;
}
@override
FileSpan get span => expression.span.expand(dot.span).expand(name.span);
FileSpan get span => expression.span.expand(op.span).expand(name.span);
}

View file

@ -47,6 +47,7 @@ enum TokenType {
plus,
minus,
elvis,
elvis_dot,
lte,
gte,
equ,
@ -54,4 +55,5 @@ enum TokenType {
number,
hex,
string,
question,
}

View file

@ -65,7 +65,7 @@ class Renderer {
msg = value.keys.fold<StringBuffer>(new StringBuffer(), (buf, k) {
var v = value[k];
if (v == null) return buf;
return buf..write('$k=$v;');
return buf..write('$k: $v;');
}).toString();
} else {
msg = value.toString();

View file

@ -2,6 +2,7 @@ part of jael.src.text.parselet;
const Map<TokenType, InfixParselet> infixParselets = const {
TokenType.lParen: const CallParselet(),
TokenType.elvis_dot: const MemberParselet(),
TokenType.dot: const MemberParselet(),
TokenType.lBracket: const IndexerParselet(),
TokenType.asterisk: const BinaryParselet(14),

View file

@ -300,6 +300,16 @@ class Parser {
while (precedence < _nextPrecedence()) {
_current = scanner.tokens[++_index];
if (_current.type == TokenType.slash && peek()?.type == TokenType.gt) {
// Handle `/>`
//
// Don't register this as an infix expression.
// Instead, backtrack, and return the current expression.
_index--;
return left;
}
var infix = infixParselets[_current.type];
var newLeft = infix.parse(this, left, _current);

View file

@ -146,9 +146,9 @@ class _Scanner implements Scanner {
// Not sure how, but the following logic seems to occur
// automatically:
//
// var textToken = tokens.removeLast();
// var newSpan = textToken.span.expand(lastToken.span);
// tokens.add(new Token(TokenType.text, newSpan));
//var textToken = tokens.removeLast();
//var newSpan = textToken.span.expand(lastToken.span);
//tokens.add(new Token(TokenType.text, newSpan));
} else if (lastToken != null) {
textStart = null;
} else if (!_scanner.isDone ?? lastToken == null) {

View file

@ -9,7 +9,7 @@ main() {
<html>
<body>
<h1>Hello</h1>
<img src=profile['avatar']>
<img src=profile['avatar'] />
</body>
</html>
''';
@ -53,6 +53,7 @@ main() {
''';
var buf = new CodeBuffer();
//jael.scan(template, sourceUrl: 'test.jl').tokens.forEach(print);
var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: {
'pokemon': const _Pokemon('Darkrai', 'Dark'),