From ea6d56660774c19830beba6ba7ae67b6b199350c Mon Sep 17 00:00:00 2001 From: "thomashii@dukefirehawk.com" Date: Thu, 29 Apr 2021 15:21:31 +0800 Subject: [PATCH] Migrated Jael --- CHANGELOG.md | 52 ++++----- packages/jael/jael/bin/jaelfmt.dart | 5 +- packages/jael/jael/lib/src/ast/array.dart | 20 ++-- packages/jael/jael/lib/src/ast/ast_node.dart | 2 +- packages/jael/jael/lib/src/ast/attribute.dart | 9 +- packages/jael/jael/lib/src/ast/binary.dart | 14 +-- packages/jael/jael/lib/src/ast/call.dart | 22 ++-- .../jael/jael/lib/src/ast/conditional.dart | 22 ++-- packages/jael/jael/lib/src/ast/document.dart | 35 +++--- packages/jael/jael/lib/src/ast/element.dart | 32 +++--- packages/jael/jael/lib/src/ast/error.dart | 6 +- .../jael/jael/lib/src/ast/expression.dart | 17 ++- .../jael/jael/lib/src/ast/identifier.dart | 22 ++-- .../jael/jael/lib/src/ast/interpolation.dart | 6 +- packages/jael/jael/lib/src/ast/map.dart | 26 ++--- packages/jael/jael/lib/src/ast/member.dart | 12 +-- packages/jael/jael/lib/src/ast/new.dart | 8 +- packages/jael/jael/lib/src/ast/number.dart | 22 ++-- packages/jael/jael/lib/src/ast/string.dart | 16 +-- packages/jael/jael/lib/src/ast/token.dart | 4 +- packages/jael/jael/lib/src/formatter.dart | 26 ++--- packages/jael/jael/lib/src/renderer.dart | 19 ++-- .../jael/lib/src/text/parselet/infix.dart | 33 +++--- .../jael/lib/src/text/parselet/parselet.dart | 4 +- .../jael/lib/src/text/parselet/prefix.dart | 30 +++--- packages/jael/jael/lib/src/text/parser.dart | 85 ++++++++------- packages/jael/jael/lib/src/text/scanner.dart | 101 ++++++++++-------- packages/jael/jael/pubspec.yaml | 2 +- packages/jael/jael/test/render/dsx_test.dart | 6 +- .../jael/jael/test/render/render_test.dart | 2 +- packages/jael/jael/test/text/common.dart | 2 +- packages/jael/jael/test/text/scan_test.dart | 2 +- 32 files changed, 352 insertions(+), 312 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e30f50d..6c93e305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # 4.0.0 (NNBD) * Changed Dart SDK requirements for all packages to ">=2.12.0 <3.0.0" to support NNBD. -* Migrated pretty_logging to 3.0.0 (0/0 tests) -* Migrated angel_http_exception to 3.0.0 (0/0 tests) +* Migrated pretty_logging to 3.0.0 (0/0 tests passed) +* Migrated angel_http_exception to 3.0.0 (0/0 tests passed) * Moved angel_cli to https://github.com/dukefirehawk/cli (Not migrated) -* Added code_buffer and migrated to 2.0.0 (16/16 tests) -* Added combinator and migrated to 2.0.0 (16/16 tests) +* Added code_buffer and migrated to 2.0.0 (16/16 tests passed) +* Added combinator and migrated to 2.0.0 (16/16 tests passed) * Migrated angel_route to 5.0.0 (35/35 tests passed) -* Migrated angel_model to 3.0.0 (0/0 tests) +* Migrated angel_model to 3.0.0 (0/0 tests passed) * Migrated angel_container to 3.0.0 (55/55 tests passed) * Added merge_map and migrated to 2.0.0 (6/6 tests passed) * Added mock_request and migrated to 2.0.0 (0/0 tests) @@ -19,7 +19,7 @@ * Migrated angel_websocket to 4.0.0 (2/3 tests passed) * Updated test to 4.0.0 (1/1 test passed) * Added symbol_table and migrated to 2.0.0 (16/16 tests passed) -* Updated jael to 3.0.0 (in progress) +* Migrated jael to 4.0.0 (17/20 tests passed) * Updated jael_preprocessor to 3.0.0 (in progress) * Updated angel_jael to 3.0.0 (in progress) * Updated pub_sub to 3.0.0 (in progress) @@ -30,27 +30,27 @@ # 3.0.0 (Non NNBD) * Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0" -* Updated pretty_logging to 2.0.0 -* Updated angel_http_exception to 2.0.0 +* Updated pretty_logging to 2.0.0 (0/0 tests passed) +* Updated angel_http_exception to 2.0.0 (0/0 tests passed) * Updated angel_cli to 3.0.0. (Rename not working) -* Updated angel_route to 4.0.0 -* Updated angel_model to 2.0.0 -* Updated angel_container to 2.0.0 -* Updated angel_framework to 3.0.0 -* Updated angel_auth to 3.0.0 -* Updated angel_configuration to 3.0.0 -* Updated angel_validate to 3.0.0 -* Added and updated json_god to 3.0.0 -* Updated angel_client to 3.0.0 -* Updated angel_websocket to 3.0.0 -* Updated jael to 3.0.0 -* Updated jael_preprocessor to 3.0.0 -* Updated test to 3.0.0 -* Updated angel_jael to 3.0.0 (Issue with 2 dependencies) -* Added pub_sub and updated to 3.0.0 -* Updated production to 2.0.0 -* Updated hot to 3.0.0 -* Updated static to 3.0.0 +* Updated angel_route to 4.0.0 (35/35 tests passed) +* Updated angel_model to 2.0.0 (0/0 tests passed) +* Updated angel_container to 2.0.0 (55/55 tests passed) +* Updated angel_framework to 3.0.0 (151/151 tests passed) +* Updated angel_auth to 3.0.0 (28/32 tests passed) +* Updated angel_configuration to 3.0.0 (6/8 tests passed) +* Updated angel_validate to 3.0.0 (7/7 tests passed) +* Added and updated json_god to 3.0.0 (7/7 tests passed) +* Updated angel_client to 3.0.0 (10/13 tests passed) +* Updated angel_websocket to 3.0.0 (3/3 tests passed) +* Updated jael to 3.0.0 (20/20 tests passed) +* Updated jael_preprocessor to 3.0.0 (5/5 tests passed) +* Updated test to 3.0.0 (1/1 tests passed) +* Updated angel_jael to 3.0.0 (1/1 tests passed, Issue with 2 dependencies) +* Added pub_sub and updated to 3.0.0 (8/16 tests passed) +* Updated production to 2.0.0 (0/0 tests passed) +* Updated hot to 3.0.0 (0/0 tests passed) +* Updated static to 3.0.0 (12/12 tests passed) * Update basic-sdk-2.12.x boilerplate * Updated angel_serialize to 3.0.0 * Updated angel_serialize_generator to 3.0.0 diff --git a/packages/jael/jael/bin/jaelfmt.dart b/packages/jael/jael/bin/jaelfmt.dart index c4935c9c..3b89acb5 100644 --- a/packages/jael/jael/bin/jaelfmt.dart +++ b/packages/jael/jael/bin/jaelfmt.dart @@ -85,7 +85,6 @@ Future formatStat( break; default: throw 'No file or directory found at "$path".'; - break; } } @@ -120,5 +119,9 @@ String? format(String? filename, String content, ArgResults argResults) { int.parse(argResults['tab-size'] as String), argResults['insert-spaces'] as bool?, int.parse(argResults['line-length'] as String)); + + if (doc == null) { + return null; + } return fmt.apply(doc); } diff --git a/packages/jael/jael/lib/src/ast/array.dart b/packages/jael/jael/lib/src/ast/array.dart index d4f93a1e..0cfb1375 100644 --- a/packages/jael/jael/lib/src/ast/array.dart +++ b/packages/jael/jael/lib/src/ast/array.dart @@ -3,7 +3,7 @@ import 'expression.dart'; import 'token.dart'; class Array extends Expression { - final Token? lBracket, rBracket; + final Token lBracket, rBracket; final List items; Array(this.lBracket, this.rBracket, this.items); @@ -14,28 +14,28 @@ class Array extends Expression { @override FileSpan get span { return items - .fold(lBracket!.span, (out, i) => out!.expand(i.span!))! - .expand(rBracket!.span!); + .fold(lBracket.span, (out, i) => out!.expand(i.span))! + .expand(rBracket.span); } } class IndexerExpression extends Expression { - final Expression? target, indexer; - final Token? lBracket, rBracket; + final Expression target, indexer; + final Token lBracket, rBracket; IndexerExpression(this.target, this.lBracket, this.indexer, this.rBracket); @override FileSpan get span { - return target!.span! - .expand(lBracket!.span!) - .expand(indexer!.span!) - .expand(rBracket!.span!); + return target.span + .expand(lBracket.span) + .expand(indexer.span) + .expand(rBracket.span); } @override dynamic compute(scope) { - var a = target!.compute(scope), b = indexer!.compute(scope); + var a = target.compute(scope), b = indexer.compute(scope); return a[b]; } } diff --git a/packages/jael/jael/lib/src/ast/ast_node.dart b/packages/jael/jael/lib/src/ast/ast_node.dart index 29f2bd67..c48971da 100644 --- a/packages/jael/jael/lib/src/ast/ast_node.dart +++ b/packages/jael/jael/lib/src/ast/ast_node.dart @@ -1,5 +1,5 @@ import 'package:source_span/source_span.dart'; abstract class AstNode { - FileSpan? get span; + FileSpan get span; } diff --git a/packages/jael/jael/lib/src/ast/attribute.dart b/packages/jael/jael/lib/src/ast/attribute.dart index 1bbbf599..d43203d0 100644 --- a/packages/jael/jael/lib/src/ast/attribute.dart +++ b/packages/jael/jael/lib/src/ast/attribute.dart @@ -15,13 +15,14 @@ class Attribute extends AstNode { bool get isRaw => nequ != null; - Expression? get nameNode => id ?? string; + Expression get nameNode => id ?? string!; String get name => string?.value ?? id!.name; @override - FileSpan? get span { - if (equals == null) return nameNode!.span; - return nameNode!.span!.expand(equals?.span ?? nequ!.span!).expand(value!.span!); + FileSpan get span { + if (equals == null || value == null) return nameNode.span; + //return nameNode.span.expand(equals!.span ?? nequ!.span).expand(value!.span); + return nameNode.span.expand(equals!.span).expand(value!.span); } } diff --git a/packages/jael/jael/lib/src/ast/binary.dart b/packages/jael/jael/lib/src/ast/binary.dart index 908f3f59..05292634 100644 --- a/packages/jael/jael/lib/src/ast/binary.dart +++ b/packages/jael/jael/lib/src/ast/binary.dart @@ -3,16 +3,16 @@ import 'expression.dart'; import 'token.dart'; class BinaryExpression extends Expression { - final Expression? left, right; - final Token? operator; + final Expression left, right; + final Token operator; BinaryExpression(this.left, this.operator, this.right); @override - compute(scope) { - var l = left!.compute(scope), r = right!.compute(scope); + dynamic compute(scope) { + var l = left.compute(scope), r = right.compute(scope); - switch (operator?.type) { + switch (operator.type) { case TokenType.asterisk: return l * r; case TokenType.slash: @@ -38,10 +38,10 @@ class BinaryExpression extends Expression { return l ?? r; default: throw UnsupportedError( - 'Unsupported binary operator: "${operator?.span?.text ?? ""}".'); + 'Unsupported binary operator: "${operator.span.text ?? ""}".'); } } @override - FileSpan get span => left!.span!.expand(operator!.span!).expand(right!.span!); + FileSpan get span => left.span.expand(operator.span).expand(right.span); } diff --git a/packages/jael/jael/lib/src/ast/call.dart b/packages/jael/jael/lib/src/ast/call.dart index e19551c7..04d905be 100644 --- a/packages/jael/jael/lib/src/ast/call.dart +++ b/packages/jael/jael/lib/src/ast/call.dart @@ -6,8 +6,8 @@ import 'identifier.dart'; import 'token.dart'; class Call extends Expression { - final Expression? target; - final Token? lParen, rParen; + final Expression target; + final Token lParen, rParen; final List arguments; final List namedArguments; @@ -17,24 +17,24 @@ class Call extends Expression { @override FileSpan get span { return arguments - .fold(target!.span, (out, a) => out!.expand(a.span!))! + .fold(target.span, (out, a) => out!.expand(a.span))! .expand(namedArguments.fold( - lParen!.span, (out, a) => out!.expand(a.span))!) - .expand(rParen!.span!); + lParen.span, (out, a) => out!.expand(a.span))!) + .expand(rParen.span); } - List computePositional(SymbolTable scope) => + List computePositional(SymbolTable? scope) => arguments.map((e) => e.compute(scope)).toList(); - Map computeNamed(SymbolTable scope) { + Map computeNamed(SymbolTable? scope) { return namedArguments.fold>({}, (out, a) { return out..[Symbol(a.name.name)] = a.value.compute(scope); }); } @override - compute(scope) { - var callee = target!.compute(scope); + dynamic compute(scope) { + var callee = target.compute(scope); var args = computePositional(scope); var named = computeNamed(scope); @@ -44,13 +44,13 @@ class Call extends Expression { class NamedArgument extends AstNode { final Identifier name; - final Token? colon; + final Token colon; final Expression value; NamedArgument(this.name, this.colon, this.value); @override FileSpan get span { - return name.span!.expand(colon!.span!).expand(value.span!); + return name.span.expand(colon.span).expand(value.span); } } diff --git a/packages/jael/jael/lib/src/ast/conditional.dart b/packages/jael/jael/lib/src/ast/conditional.dart index d3491193..f96a1958 100644 --- a/packages/jael/jael/lib/src/ast/conditional.dart +++ b/packages/jael/jael/lib/src/ast/conditional.dart @@ -3,29 +3,29 @@ import 'expression.dart'; import 'token.dart'; class Conditional extends Expression { - final Expression? condition, ifTrue, ifFalse; - final Token? question, colon; + final Expression condition, ifTrue, ifFalse; + final Token question, colon; Conditional( this.condition, this.question, this.ifTrue, this.colon, this.ifFalse); @override FileSpan get span { - return condition!.span! - .expand(question!.span!) - .expand(ifTrue!.span!) - .expand(colon!.span!) - .expand(ifFalse!.span!); + return condition.span + .expand(question.span) + .expand(ifTrue.span) + .expand(colon.span) + .expand(ifFalse.span); } @override - compute(scope) { - var v = condition!.compute(scope) as bool?; + dynamic compute(scope) { + var v = condition.compute(scope) as bool; - if (scope.resolve('!strict!')?.value == false) { + if (scope?.resolve('!strict!')?.value == false) { v = v == true; } - return v! ? ifTrue!.compute(scope) : ifFalse!.compute(scope); + return v ? ifTrue.compute(scope) : ifFalse.compute(scope); } } diff --git a/packages/jael/jael/lib/src/ast/document.dart b/packages/jael/jael/lib/src/ast/document.dart index 04c8198e..09a7a974 100644 --- a/packages/jael/jael/lib/src/ast/document.dart +++ b/packages/jael/jael/lib/src/ast/document.dart @@ -12,33 +12,34 @@ class Document extends AstNode { Document(this.doctype, this.root); @override - FileSpan? get span { + FileSpan get span { if (doctype == null) return root.span; - return doctype!.span.expand(root.span!); + return doctype!.span.expand(root.span); } } class HtmlComment extends ElementChild { - final Token? htmlComment; + final Token htmlComment; HtmlComment(this.htmlComment); @override - FileSpan? get span => htmlComment!.span; + FileSpan get span => htmlComment.span; } class Text extends ElementChild { - final Token? text; + final Token text; Text(this.text); @override - FileSpan? get span => text!.span; + FileSpan get span => text.span; } class Doctype extends AstNode { - final Token? lt, doctype, gt; - final Identifier? html, public; + final Token lt, doctype, gt; + final Identifier html; + final Identifier? public; final StringLiteral? name, url; Doctype(this.lt, this.doctype, this.html, this.public, this.name, this.url, @@ -46,15 +47,15 @@ class Doctype extends AstNode { @override FileSpan get span { - if (public == null) { - return lt!.span!.expand(doctype!.span!).expand(html!.span!).expand(gt!.span!); + if (public == null || name == null || url == null) { + return lt.span.expand(doctype.span).expand(html.span).expand(gt.span); } - return lt!.span! - .expand(doctype!.span!) - .expand(html!.span!) - .expand(public!.span!) - .expand(name!.span!) - .expand(url!.span!) - .expand(gt!.span!); + return lt.span + .expand(doctype.span) + .expand(html.span) + .expand(public!.span) + .expand(name!.span) + .expand(url!.span) + .expand(gt.span); } } diff --git a/packages/jael/jael/lib/src/ast/element.dart b/packages/jael/jael/lib/src/ast/element.dart index 5a359061..c7ad7205 100644 --- a/packages/jael/jael/lib/src/ast/element.dart +++ b/packages/jael/jael/lib/src/ast/element.dart @@ -13,7 +13,7 @@ class TextNode extends ElementChild { TextNode(this.text); @override - FileSpan? get span => text.span; + FileSpan get span => text.span; } abstract class Element extends ElementChild { @@ -44,10 +44,13 @@ abstract class Element extends ElementChild { } class SelfClosingElement extends Element { - final Token? lt, slash, gt; + final Token? slash; + final Token lt, gt; + @override final Identifier tagName; + @override final Iterable attributes; @override @@ -59,20 +62,19 @@ class SelfClosingElement extends Element { @override FileSpan get span { var start = attributes.fold( - lt!.span!.expand(tagName.span!), (out, a) => out.expand(a.span!)); + lt.span.expand(tagName.span), (out, a) => out.expand(a.span)); return slash != null - ? start.expand(slash!.span!).expand(gt!.span!) - : start.expand(gt!.span!); + ? start.expand(slash!.span).expand(gt.span) + : start.expand(gt.span); } } class RegularElement extends Element { - final Token? lt, gt, lt2, slash, gt2; + final Token? gt2; + final Token lt2, slash, lt, gt; final Identifier tagName, tagName2; - final Iterable attributes; - final Iterable children; RegularElement(this.lt, this.tagName, this.attributes, this.gt, this.children, @@ -82,16 +84,16 @@ class RegularElement extends Element { FileSpan get span { var openingTag = attributes .fold( - lt!.span!.expand(tagName.span!), (out, a) => out.expand(a.span!)) - .expand(gt!.span!); + lt.span.expand(tagName.span), (out, a) => out.expand(a.span)) + .expand(gt.span); if (gt2 == null) return openingTag; return children - .fold(openingTag, (out, c) => out.expand(c.span!)) - .expand(lt2!.span!) - .expand(slash!.span!) - .expand(tagName2.span!) - .expand(gt2!.span!); + .fold(openingTag, (out, c) => out.expand(c.span)) + .expand(lt2.span) + .expand(slash.span) + .expand(tagName2.span) + .expand(gt2!.span); } } diff --git a/packages/jael/jael/lib/src/ast/error.dart b/packages/jael/jael/lib/src/ast/error.dart index 66784d5b..f931a126 100644 --- a/packages/jael/jael/lib/src/ast/error.dart +++ b/packages/jael/jael/lib/src/ast/error.dart @@ -3,15 +3,15 @@ import 'package:source_span/source_span.dart'; class JaelError extends Error { final JaelErrorSeverity severity; final String message; - final FileSpan? span; + final FileSpan span; JaelError(this.severity, this.message, this.span); @override String toString() { var label = severity == JaelErrorSeverity.warning ? 'warning' : 'error'; - return '$label: ${span!.start.toolString}: $message\n' + - span!.highlight(color: true); + return '$label: ${span.start.toolString}: $message\n' + + span.highlight(color: true); } } diff --git a/packages/jael/jael/lib/src/ast/expression.dart b/packages/jael/jael/lib/src/ast/expression.dart index 851312b7..db20fee8 100644 --- a/packages/jael/jael/lib/src/ast/expression.dart +++ b/packages/jael/jael/lib/src/ast/expression.dart @@ -4,30 +4,29 @@ import 'ast_node.dart'; import 'token.dart'; abstract class Expression extends AstNode { - dynamic compute(SymbolTable scope); + dynamic compute(SymbolTable? scope); } abstract class Literal extends Expression {} class Negation extends Expression { - final Token? exclamation; - final Expression? expression; + final Token exclamation; + final Expression expression; Negation(this.exclamation, this.expression); @override FileSpan get span { - return exclamation!.span!.expand(expression!.span!); + return exclamation.span.expand(expression.span); } @override - compute(SymbolTable scope) { - var v = expression!.compute(scope) as bool?; - - if (scope.resolve('!strict!')?.value == false) { + bool compute(SymbolTable? scope) { + var v = expression.compute(scope) as bool; + if (scope?.resolve('!strict!')?.value == false) { v = v == true; } - return !v!; + return !v; } } diff --git a/packages/jael/jael/lib/src/ast/identifier.dart b/packages/jael/jael/lib/src/ast/identifier.dart index da95c2d4..135d1d97 100644 --- a/packages/jael/jael/lib/src/ast/identifier.dart +++ b/packages/jael/jael/lib/src/ast/identifier.dart @@ -4,12 +4,12 @@ import 'expression.dart'; import 'token.dart'; class Identifier extends Expression { - final Token? id; + final Token id; Identifier(this.id); @override - compute(SymbolTable scope) { + dynamic compute(SymbolTable? scope) { switch (name) { case 'null': return null; @@ -18,30 +18,30 @@ class Identifier extends Expression { case 'false': return false; default: - var symbol = scope.resolve(name); + var symbol = scope?.resolve(name); if (symbol == null) { - if (scope.resolve('!strict!')?.value == false) return null; + if (scope?.resolve('!strict!')?.value == false) return null; throw ArgumentError('The name "$name" does not exist in this scope.'); } - return scope.resolve(name)!.value; + return scope?.resolve(name)!.value; } } - String get name => id!.span!.text; + String get name => id.span.text ?? ''; @override - FileSpan? get span => id!.span; + FileSpan get span => id.span; } class SyntheticIdentifier extends Identifier { @override final String name; - SyntheticIdentifier(this.name, [Token? token]) : super(token); + SyntheticIdentifier(this.name, [Token? token]) : super(token!); @override - FileSpan? get span { - if (id != null) return id!.span; - throw UnsupportedError('Cannot get the span of a SyntheticIdentifier.'); + FileSpan get span { + return id.span; + //throw UnsupportedError('Cannot get the span of a SyntheticIdentifier.'); } } diff --git a/packages/jael/jael/lib/src/ast/interpolation.dart b/packages/jael/jael/lib/src/ast/interpolation.dart index 331011ba..5688c734 100644 --- a/packages/jael/jael/lib/src/ast/interpolation.dart +++ b/packages/jael/jael/lib/src/ast/interpolation.dart @@ -4,15 +4,15 @@ import 'expression.dart'; import 'token.dart'; class Interpolation extends ElementChild { - final Token? doubleCurlyL, doubleCurlyR; + final Token doubleCurlyL, doubleCurlyR; final Expression expression; Interpolation(this.doubleCurlyL, this.expression, this.doubleCurlyR); - bool get isRaw => doubleCurlyL!.span!.text.endsWith('-'); + bool get isRaw => doubleCurlyL.span.text?.endsWith('-') ?? false; @override FileSpan get span { - return doubleCurlyL!.span!.expand(expression.span!).expand(doubleCurlyR!.span!); + return doubleCurlyL.span.expand(expression.span).expand(doubleCurlyR.span); } } diff --git a/packages/jael/jael/lib/src/ast/map.dart b/packages/jael/jael/lib/src/ast/map.dart index 23078a1e..4243bdcf 100644 --- a/packages/jael/jael/lib/src/ast/map.dart +++ b/packages/jael/jael/lib/src/ast/map.dart @@ -5,26 +5,26 @@ import 'identifier.dart'; import 'token.dart'; class MapLiteral extends Literal { - final Token? lCurly, rCurly; + final Token lCurly, rCurly; final List pairs; MapLiteral(this.lCurly, this.pairs, this.rCurly); @override - compute(scope) { + Map compute(scope) { return pairs.fold({}, (out, p) { var key, value; if (p.colon == null) { if (p.key is! Identifier) { - key = value = p.key!.compute(scope); + key = value = p.key.compute(scope); } else { key = (p.key as Identifier).name; - value = p.key!.compute(scope); + value = p.key.compute(scope); } } else { - key = p.key!.compute(scope); - value = p.value!.compute(scope); + key = p.key.compute(scope); + value = p.value?.compute(scope); } return out..[key] = value; @@ -34,20 +34,22 @@ class MapLiteral extends Literal { @override FileSpan get span { return pairs - .fold(lCurly!.span, (out, p) => out!.expand(p.span!))! - .expand(rCurly!.span!); + .fold(lCurly.span, (out, p) => out?.expand(p.span))! + .expand(rCurly.span); } } class KeyValuePair extends AstNode { - final Expression? key, value; + final Expression key; + final Expression? value; + final Token? colon; KeyValuePair(this.key, this.colon, this.value); @override - FileSpan? get span { - if (colon == null) return key!.span; - return colon!.span!.expand(colon!.span!).expand(value!.span!); + FileSpan get span { + if (colon == null || value == null) return key.span; + return colon!.span.expand(colon!.span).expand(value!.span); } } diff --git a/packages/jael/jael/lib/src/ast/member.dart b/packages/jael/jael/lib/src/ast/member.dart index 86751fbe..1b0ebf72 100644 --- a/packages/jael/jael/lib/src/ast/member.dart +++ b/packages/jael/jael/lib/src/ast/member.dart @@ -6,19 +6,19 @@ import 'identifier.dart'; import 'token.dart'; class MemberExpression extends Expression { - final Expression? expression; - final Token? op; + final Expression expression; + final Token op; final Identifier 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; + dynamic compute(SymbolTable? scope) { + var target = expression.compute(scope); + if (op.span.text == '?.' && target == null) return null; return reflect(target).getField(Symbol(name.name)).reflectee; } @override - FileSpan get span => expression!.span!.expand(op!.span!).expand(name.span!); + FileSpan get span => expression.span.expand(op.span).expand(name.span); } diff --git a/packages/jael/jael/lib/src/ast/new.dart b/packages/jael/jael/lib/src/ast/new.dart index 57ec6be2..19762ccc 100644 --- a/packages/jael/jael/lib/src/ast/new.dart +++ b/packages/jael/jael/lib/src/ast/new.dart @@ -6,17 +6,17 @@ import 'member.dart'; import 'token.dart'; class NewExpression extends Expression { - final Token? $new; + final Token $new; final Call call; NewExpression(this.$new, this.call); @override - FileSpan get span => $new!.span!.expand(call.span); + FileSpan get span => $new.span.expand(call.span); @override - compute(scope) { - var targetType = call.target!.compute(scope); + dynamic compute(scope) { + var targetType = call.target.compute(scope); var positional = call.computePositional(scope); var named = call.computeNamed(scope); var name = ''; diff --git a/packages/jael/jael/lib/src/ast/number.dart b/packages/jael/jael/lib/src/ast/number.dart index c91dc48f..9847039f 100644 --- a/packages/jael/jael/lib/src/ast/number.dart +++ b/packages/jael/jael/lib/src/ast/number.dart @@ -4,13 +4,13 @@ import 'expression.dart'; import 'token.dart'; class NumberLiteral extends Literal { - final Token? number; + final Token number; num? _value; NumberLiteral(this.number); @override - FileSpan? get span => number!.span; + FileSpan get span => number.span; static num parse(String value) { var e = value.indexOf('E'); @@ -24,24 +24,30 @@ class NumberLiteral extends Literal { } @override - compute(scope) { - return _value ??= parse(number!.span!.text); + num compute(scope) { + if (number.span.text == null) { + return 0; + } + return _value ??= parse(number.span.text!); } } class HexLiteral extends Literal { - final Token? hex; + final Token hex; num? _value; HexLiteral(this.hex); @override - FileSpan? get span => hex!.span; + FileSpan get span => hex.span; static num parse(String value) => int.parse(value.substring(2), radix: 16); @override - compute(scope) { - return _value ??= parse(hex!.span!.text); + num compute(scope) { + if (hex.span.text == null) { + return 0; + } + return _value ??= parse(hex.span.text!); } } diff --git a/packages/jael/jael/lib/src/ast/string.dart b/packages/jael/jael/lib/src/ast/string.dart index 3a87c3ae..42f97916 100644 --- a/packages/jael/jael/lib/src/ast/string.dart +++ b/packages/jael/jael/lib/src/ast/string.dart @@ -6,17 +6,21 @@ import 'expression.dart'; import 'token.dart'; class StringLiteral extends Literal { - final Token? string; + final Token string; final String value; StringLiteral(this.string, this.value); static String parseValue(Token string) { - var text = string.span!.text.substring(1, string.span!.text.length - 1); - var codeUnits = text.codeUnits; var buf = StringBuffer(); + if (string.span.text == null) { + return buf.toString(); + } - for (int i = 0; i < codeUnits.length; i++) { + var text = string.span.text!.substring(1, string.span.text!.length - 1); + var codeUnits = text.codeUnits; + + for (var i = 0; i < codeUnits.length; i++) { var ch = codeUnits[i]; if (ch == $backslash) { @@ -66,10 +70,10 @@ class StringLiteral extends Literal { } @override - compute(SymbolTable scope) { + String compute(SymbolTable? scope) { return value; } @override - FileSpan? get span => string!.span; + FileSpan get span => string.span; } diff --git a/packages/jael/jael/lib/src/ast/token.dart b/packages/jael/jael/lib/src/ast/token.dart index 54deaf6b..5da519d7 100644 --- a/packages/jael/jael/lib/src/ast/token.dart +++ b/packages/jael/jael/lib/src/ast/token.dart @@ -2,14 +2,14 @@ import 'package:source_span/source_span.dart'; class Token { final TokenType type; - final FileSpan? span; + final FileSpan span; final Match? match; Token(this.type, this.span, this.match); @override String toString() { - return '${span!.start.toolString}: "${span!.text}" => $type'; + return '${span.start.toolString}: "${span.text}" => $type'; } } diff --git a/packages/jael/jael/lib/src/formatter.dart b/packages/jael/jael/lib/src/formatter.dart index 3b46ed7c..03582c3c 100644 --- a/packages/jael/jael/lib/src/formatter.dart +++ b/packages/jael/jael/lib/src/formatter.dart @@ -5,13 +5,13 @@ class JaelFormatter { final num tabSize; final bool? insertSpaces; final int maxLineLength; - var _buffer = StringBuffer(); + final _buffer = StringBuffer(); int _level = 0; String? _spaces; static String _spaceString(int tabSize) { var b = StringBuffer(); - for (int i = 0; i < tabSize; i++) { + for (var i = 0; i < tabSize; i++) { b.write(' '); } return b.toString(); @@ -30,34 +30,34 @@ class JaelFormatter { } void _applySpacing() { - for (int i = 0; i < _level; i++) { + for (var i = 0; i < _level; i++) { _buffer.write(_spaces); } } int get _spaceLength { var out = 0; - for (int i = 0; i < _level; i++) { + for (var i = 0; i < _level; i++) { out += _spaces!.length; } return out; } - String apply(Document? document) { - if (document?.doctype != null) { + String apply(Document document) { + if (document.doctype != null) { _buffer.write(''); } - _formatChild(document?.root, 0); + _formatChild(document.root, 0); return _buffer.toString().trim(); } @@ -72,11 +72,11 @@ class JaelFormatter { var b = StringBuffer('{{'); if (child.isRaw) b.write('-'); b.write(' '); - b.write(child.expression.span!.text.trim()); + b.write(child.expression.span.text?.trim()); b.write(' }}'); s = b.toString(); } else { - s = child.span!.text; + s = child.span.text ?? ''; } if (isFirst) { s = s.trimLeft(); @@ -186,7 +186,7 @@ class JaelFormatter { } else { if (attr.nequ != null) b.write('!='); if (attr.equals != null) b.write('='); - b.write(attr.value!.span!.text); + b.write(attr.value!.span.text); } } return b.toString(); diff --git a/packages/jael/jael/lib/src/renderer.dart b/packages/jael/jael/lib/src/renderer.dart index 43d4cd5c..8f158c8e 100644 --- a/packages/jael/jael/lib/src/renderer.dart +++ b/packages/jael/jael/lib/src/renderer.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:code_buffer/code_buffer.dart'; import 'package:collection/collection.dart' show IterableExtension; +import 'package:source_span/source_span.dart'; import 'package:symbol_table/symbol_table.dart'; import 'ast/ast.dart'; import 'text/parser.dart'; @@ -8,7 +9,7 @@ import 'text/scanner.dart'; /// Parses a Jael document. Document? parseDocument(String text, - {sourceUrl, bool asDSX = false, void onError(JaelError error)?}) { + {sourceUrl, bool asDSX = false, void Function(JaelError error)? onError}) { var scanner = scan(text, sourceUrl: sourceUrl, asDSX: asDSX); //scanner.tokens.forEach(print); @@ -56,12 +57,12 @@ class Renderer { ..writeln('
  • ') ..indent() ..writeln( - '$type: ${error.span!.start.toolString}: ${error.message}') + '$type: ${error.span.start.toolString}: ${error.message}') ..writeln('
    ') ..writeln( '' + htmlEscape - .convert(error.span!.highlight(color: false)) + .convert(error.span.highlight(color: false)) .replaceAll('\n', '
    ') + '
    ', ) @@ -161,7 +162,7 @@ class Renderer { buffer.writeln('>'); buffer.indent(); - for (int i = 0; i < element.children.length; i++) { + for (var i = 0; i < element.children.length; i++) { var child = element.children.elementAt(i); renderElementChild(element, child, buffer, childScope, html5, i, element.children.length); @@ -278,7 +279,7 @@ class Renderer { ?.value ?.compute(scope); if (comparison == value) { - for (int i = 0; i < child.children.length; i++) { + for (var i = 0; i < child.children.length; i++) { var c = child.children.elementAt(i); renderElementChild( element, c, buffer, scope, html5, i, child.children.length); @@ -303,11 +304,11 @@ class Renderer { SymbolTable scope, bool html5, int index, int total) { if (child is Text && parent.tagName.name != 'textarea') { if (index == 0) { - buffer.write(child.span!.text.trimLeft()); + buffer.write(child.span.text?.trimLeft()); } else if (index == total - 1) { - buffer.write(child.span!.text.trimRight()); + buffer.write(child.span.text?.trimRight()); } else { - buffer.write(child.span!.text); + buffer.write(child.span.text); } } else if (child is Interpolation) { var value = child.expression.compute(scope); @@ -369,7 +370,7 @@ class Renderer { } if (renderAs == false) { - for (int i = 0; i < template!.children.length; i++) { + for (var i = 0; i < template!.children.length; i++) { var child = template.children.elementAt(i); renderElementChild( element, child, buffer, scope, html5, i, element.children.length); diff --git a/packages/jael/jael/lib/src/text/parselet/infix.dart b/packages/jael/jael/lib/src/text/parselet/infix.dart index 9a5a27aa..31c56399 100644 --- a/packages/jael/jael/lib/src/text/parselet/infix.dart +++ b/packages/jael/jael/lib/src/text/parselet/infix.dart @@ -28,12 +28,12 @@ class ConditionalParselet implements InfixParselet { const ConditionalParselet(); @override - Expression? parse(Parser parser, Expression? left, Token? token) { + Expression? parse(Parser parser, Expression left, Token token) { var ifTrue = parser.parseExpression(0); if (ifTrue == null) { parser.errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression in conditional expression.', token!.span)); + 'Missing expression in conditional expression.', token.span)); return null; } @@ -48,7 +48,7 @@ class ConditionalParselet implements InfixParselet { if (ifFalse == null) { parser.errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression in conditional expression.', colon!.span)); + 'Missing expression in conditional expression.', colon.span)); return null; } @@ -57,19 +57,20 @@ class ConditionalParselet implements InfixParselet { } class BinaryParselet implements InfixParselet { + @override final int precedence; const BinaryParselet(this.precedence); @override - Expression? parse(Parser parser, Expression? left, Token? token) { + Expression? parse(Parser parser, Expression left, Token token) { var right = parser.parseExpression(precedence); if (right == null) { - if (token!.type != TokenType.gt) { + if (token.type != TokenType.gt) { parser.errors.add(JaelError( JaelErrorSeverity.error, - 'Missing expression after operator "${token.span!.text}", following expression ${left!.span!.text}.', + 'Missing expression after operator "${token.span.text}", following expression ${left.span.text}.', token.span)); } return null; @@ -86,10 +87,10 @@ class CallParselet implements InfixParselet { int get precedence => 19; @override - Expression? parse(Parser parser, Expression? left, Token? token) { - List arguments = []; - List namedArguments = []; - Expression? argument = parser.parseExpression(0); + Expression? parse(Parser parser, Expression left, Token token) { + var arguments = []; + var namedArguments = []; + var argument = parser.parseExpression(0); while (argument != null) { arguments.add(argument); @@ -98,7 +99,7 @@ class CallParselet implements InfixParselet { argument = parser.parseExpression(0); } - NamedArgument? namedArgument = parser.parseNamedArgument(); + var namedArgument = parser.parseNamedArgument(); while (namedArgument != null) { namedArguments.add(namedArgument); @@ -109,7 +110,7 @@ class CallParselet implements InfixParselet { if (!parser.next(TokenType.rParen)) { var lastSpan = arguments.isEmpty ? null : arguments.last.span; - lastSpan ??= token!.span; + lastSpan ??= token.span; parser.errors.add(JaelError(JaelErrorSeverity.error, 'Missing ")" after argument list.', lastSpan)); return null; @@ -126,12 +127,12 @@ class IndexerParselet implements InfixParselet { int get precedence => 19; @override - Expression? parse(Parser parser, Expression? left, Token? token) { + Expression? parse(Parser parser, Expression left, Token token) { var indexer = parser.parseExpression(0); if (indexer == null) { parser.errors.add(JaelError( - JaelErrorSeverity.error, 'Missing expression after "[".', left!.span)); + JaelErrorSeverity.error, 'Missing expression after "[".', left.span)); return null; } @@ -152,12 +153,12 @@ class MemberParselet implements InfixParselet { int get precedence => 19; @override - Expression? parse(Parser parser, Expression? left, Token? token) { + Expression? parse(Parser parser, Expression left, Token token) { var name = parser.parseIdentifier(); if (name == null) { parser.errors.add(JaelError(JaelErrorSeverity.error, - 'Expected the name of a property following "."', token!.span)); + 'Expected the name of a property following "."', token.span)); return null; } diff --git a/packages/jael/jael/lib/src/text/parselet/parselet.dart b/packages/jael/jael/lib/src/text/parselet/parselet.dart index 72f9e9e9..1f073c37 100644 --- a/packages/jael/jael/lib/src/text/parselet/parselet.dart +++ b/packages/jael/jael/lib/src/text/parselet/parselet.dart @@ -6,10 +6,10 @@ part 'infix.dart'; part 'prefix.dart'; abstract class PrefixParselet { - Expression? parse(Parser parser, Token? token); + Expression? parse(Parser parser, Token token); } abstract class InfixParselet { int get precedence; - Expression? parse(Parser parser, Expression? left, Token? token); + Expression? parse(Parser parser, Expression left, Token token); } diff --git a/packages/jael/jael/lib/src/text/parselet/prefix.dart b/packages/jael/jael/lib/src/text/parselet/prefix.dart index ada46bcc..34dd230c 100644 --- a/packages/jael/jael/lib/src/text/parselet/prefix.dart +++ b/packages/jael/jael/lib/src/text/parselet/prefix.dart @@ -16,15 +16,15 @@ class NotParselet implements PrefixParselet { const NotParselet(); @override - Expression parse(Parser parser, Token? token) { + Expression parse(Parser parser, Token token) { var expression = parser.parseExpression(0); if (expression == null) { parser.errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression after "!" in negation expression.', token!.span)); + 'Missing expression after "!" in negation expression.', token.span)); } - return Negation(token, expression); + return Negation(token, expression!); } } @@ -32,7 +32,7 @@ class NewParselet implements PrefixParselet { const NewParselet(); @override - Expression? parse(Parser parser, Token? token) { + Expression? parse(Parser parser, Token token) { var call = parser.parseExpression(0); if (call == null) { @@ -57,31 +57,31 @@ class NumberParselet implements PrefixParselet { const NumberParselet(); @override - Expression parse(Parser parser, Token? token) => NumberLiteral(token); + Expression parse(Parser parser, Token token) => NumberLiteral(token); } class HexParselet implements PrefixParselet { const HexParselet(); @override - Expression parse(Parser parser, Token? token) => HexLiteral(token); + Expression parse(Parser parser, Token token) => HexLiteral(token); } class StringParselet implements PrefixParselet { const StringParselet(); @override - Expression parse(Parser parser, Token? token) => - StringLiteral(token, StringLiteral.parseValue(token!)); + Expression parse(Parser parser, Token token) => + StringLiteral(token, StringLiteral.parseValue(token)); } class ArrayParselet implements PrefixParselet { const ArrayParselet(); @override - Expression? parse(Parser parser, Token? token) { - List items = []; - Expression? item = parser.parseExpression(0); + Expression? parse(Parser parser, Token token) { + var items = []; + var item = parser.parseExpression(0); while (item != null) { items.add(item); @@ -92,7 +92,7 @@ class ArrayParselet implements PrefixParselet { if (!parser.next(TokenType.rBracket)) { var lastSpan = items.isEmpty ? null : items.last.span; - lastSpan ??= token!.span; + lastSpan ??= token.span; parser.errors.add(JaelError(JaelErrorSeverity.error, 'Missing "]" to terminate array literal.', lastSpan)); return null; @@ -106,7 +106,7 @@ class MapParselet implements PrefixParselet { const MapParselet(); @override - Expression? parse(Parser parser, Token? token) { + Expression? parse(Parser parser, Token token) { var pairs = []; var pair = parser.parseKeyValuePair(); @@ -118,7 +118,7 @@ class MapParselet implements PrefixParselet { } if (!parser.next(TokenType.rCurly)) { - var lastSpan = pairs.isEmpty ? token!.span : pairs.last.span; + var lastSpan = pairs.isEmpty ? token.span : pairs.last.span; parser.errors.add(JaelError( JaelErrorSeverity.error, 'Missing "}" in map literal.', lastSpan)); return null; @@ -132,7 +132,7 @@ class IdentifierParselet implements PrefixParselet { const IdentifierParselet(); @override - Expression parse(Parser parser, Token? token) => Identifier(token); + Expression parse(Parser parser, Token token) => Identifier(token); } class ParenthesisParselet implements PrefixParselet { diff --git a/packages/jael/jael/lib/src/text/parser.dart b/packages/jael/jael/lib/src/text/parser.dart index c3c26b9e..18b5c2a4 100644 --- a/packages/jael/jael/lib/src/text/parser.dart +++ b/packages/jael/jael/lib/src/text/parser.dart @@ -7,12 +7,12 @@ class Parser { final Scanner scanner; final bool asDSX; - Token? _current; + late Token _current; int _index = -1; Parser(this.scanner, {this.asDSX = false}); - Token? get current => _current; + Token get current => _current; int _nextPrecedence() { var tok = peek(); @@ -68,8 +68,11 @@ class Parser { StringLiteral? implicitString() { if (next(TokenType.string)) { - return prefixParselets[TokenType.string]!.parse(this, _current) - as StringLiteral?; + var result = prefixParselets[TokenType.string]?.parse(this, _current); + if (result != null) { + return result as StringLiteral; + } + return null; } /*else if (next(TokenType.text)) { @@ -86,12 +89,14 @@ class Parser { _index--; return null; } - var doctype = _current, html = parseIdentifier() as Token?; - if (html?.span?.text.toLowerCase() != 'html') { + var doctype = _current; + var html = parseIdentifier(); + if (html == null || html.span.text?.toLowerCase() != 'html') { errors.add(JaelError( JaelErrorSeverity.error, 'Expected "html" in doctype declaration.', - html?.span ?? doctype!.span)); + html?.span ?? doctype.span)); + return null; } @@ -99,19 +104,23 @@ class Parser { if (public == null) { if (!next(TokenType.gt)) { errors.add(JaelError(JaelErrorSeverity.error, - 'Expected ">" in doctype declaration.', html!.span)); + 'Expected ">" in doctype declaration.', html.span)); + // ?? doctype.span)); return null; } - return Doctype( - lt, doctype, html as Identifier?, null, null, null, _current); + return Doctype(lt, doctype, html, null, null, null, _current); } - if (public.span?.text.toLowerCase() != 'public') { - errors.add(JaelError( - JaelErrorSeverity.error, - 'Expected "public" in doctype declaration.', - public.span ?? html!.span)); + if (public.span.text?.toLowerCase() != 'public') { + //errors.add(JaelError( + // JaelErrorSeverity.error, + // 'Expected "public" in doctype declaration.', + // public!.span ?? html?.span)); + + errors.add(JaelError(JaelErrorSeverity.error, + 'Expected "public" in doctype declaration.', public.span)); + return null; } @@ -123,24 +132,23 @@ class Parser { return null; } - var name = stringParser!.parse(this, _current) as StringLiteral?; + var name = stringParser?.parse(this, _current) as StringLiteral; if (!next(TokenType.string)) { errors.add(JaelError(JaelErrorSeverity.error, - 'Expected string in doctype declaration.', name!.span)); + 'Expected string in doctype declaration.', name.span)); return null; } - var url = stringParser.parse(this, _current) as StringLiteral?; + var url = stringParser?.parse(this, _current) as StringLiteral; if (!next(TokenType.gt)) { errors.add(JaelError(JaelErrorSeverity.error, - 'Expected ">" in doctype declaration.', url!.span)); + 'Expected ">" in doctype declaration.', url.span)); return null; } - return Doctype( - lt, doctype, html as Identifier?, public, name, url, _current); + return Doctype(lt, doctype, html, public, name, url, _current); } ElementChild? parseElementChild() => @@ -162,7 +170,7 @@ class Parser { if (expression == null) { errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression in interpolation.', doubleCurlyL!.span)); + 'Missing expression in interpolation.', doubleCurlyL.span)); return null; } @@ -190,7 +198,7 @@ class Parser { if (tagName == null) { errors.add( - JaelError(JaelErrorSeverity.error, 'Missing tag name.', lt!.span)); + JaelError(JaelErrorSeverity.error, 'Missing tag name.', lt.span)); return null; } @@ -208,7 +216,7 @@ class Parser { if (!next(TokenType.gt)) { errors.add(JaelError(JaelErrorSeverity.error, - 'Missing ">" in self-closing "${tagName.name}" tag.', slash!.span)); + 'Missing ">" in self-closing "${tagName.name}" tag.', slash.span)); return null; } @@ -252,7 +260,7 @@ class Parser { if (!next(TokenType.slash)) { errors.add(JaelError(JaelErrorSeverity.error, - 'Missing "/" in "${tagName.name}" closing tag.', lt2!.span)); + 'Missing "/" in "${tagName.name}" closing tag.', lt2.span)); return null; } @@ -263,15 +271,15 @@ class Parser { errors.add(JaelError( JaelErrorSeverity.error, 'Missing "${tagName.name}" in "${tagName.name}" closing tag.', - slash!.span)); + slash.span)); return null; } if (tagName2.name != tagName.name) { errors.add(JaelError( JaelErrorSeverity.error, - 'Mismatched closing tags. Expected "${tagName.span!.text}"; got "${tagName2.name}" instead.', - lt2!.span)); + 'Mismatched closing tags. Expected "${tagName.span.text}"; got "${tagName2.name}" instead.', + lt2.span)); return null; } @@ -292,7 +300,7 @@ class Parser { if ((id = parseIdentifier()) != null) { // Nothing } else if (next(TokenType.string)) { - string = StringLiteral(_current, StringLiteral.parseValue(_current!)); + string = StringLiteral(_current, StringLiteral.parseValue(_current)); } else { return null; } @@ -342,12 +350,12 @@ class Parser { for (var type in prefixParselets.keys) { if (next(type)) { - var left = prefixParselets[type]!.parse(this, _current); + var left = prefixParselets[type]?.parse(this, _current); while (precedence < _nextPrecedence()) { _current = scanner.tokens[++_index]; - if (_current!.type == TokenType.slash && + if (_current.type == TokenType.slash && peek()?.type == TokenType.gt) { // Handle `/>` // @@ -357,11 +365,14 @@ class Parser { return left; } - var infix = infixParselets[_current!.type]!; - var newLeft = infix.parse(this, left, _current); + var infix = infixParselets[_current.type]!; + Expression? newLeft; + if (left != null) { + newLeft = infix.parse(this, left, _current); + } if (newLeft == null) { - if (_current!.type == TokenType.gt) _index--; + if (_current.type == TokenType.gt) _index--; return left; } left = newLeft; @@ -388,11 +399,11 @@ class Parser { if (value == null) { errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression in key-value pair.', colon!.span)); + 'Missing expression in key-value pair.', colon.span)); return null; } - return KeyValuePair(key, colon, value as Expression?); + return KeyValuePair(key, colon, value as Expression); } NamedArgument? parseNamedArgument() { @@ -409,7 +420,7 @@ class Parser { if (value == null) { errors.add(JaelError(JaelErrorSeverity.error, - 'Missing expression in named argument.', colon!.span)); + 'Missing expression in named argument.', colon.span)); return null; } diff --git a/packages/jael/jael/lib/src/text/scanner.dart b/packages/jael/jael/lib/src/text/scanner.dart index 24f26e3d..5e1113e7 100644 --- a/packages/jael/jael/lib/src/text/scanner.dart +++ b/packages/jael/jael/lib/src/text/scanner.dart @@ -55,7 +55,7 @@ final Map _expressionPatterns = { '.': TokenType.dot, '??': TokenType.elvis, '?.': TokenType.elvis_dot, - '=': TokenType.equals, + //'=': TokenType.equals, '!': TokenType.exclamation, '-': TokenType.minus, '%': TokenType.percent, @@ -66,14 +66,14 @@ final Map _expressionPatterns = { '}': TokenType.rCurly, '(': TokenType.lParen, ')': TokenType.rParen, - '/': TokenType.slash, - '<': TokenType.lt, + //'/': TokenType.slash, + //'<': TokenType.lt, '<=': TokenType.lte, - '>': TokenType.gt, + //'>': TokenType.gt, '>=': TokenType.gte, '==': TokenType.equ, - '!=': TokenType.nequ, - '=': TokenType.equals, + //'!=': TokenType.nequ, + //'=': TokenType.equals, RegExp(r'-?[0-9]+(\.[0-9]+)?([Ee][0-9]+)?'): TokenType.number, RegExp(r'0x[A-Fa-f0-9]+'): TokenType.hex, _string1: TokenType.string, @@ -82,47 +82,50 @@ final Map _expressionPatterns = { }; class _Scanner implements Scanner { + @override final List errors = []; + + @override final List tokens = []; _ScannerState state = _ScannerState.html; final Queue openTags = Queue(); - SpanScanner? _scanner; + late SpanScanner _scanner; _Scanner(String text, sourceUrl) { _scanner = SpanScanner(text, sourceUrl: sourceUrl); } void scan({bool asDSX = false}) { - while (!_scanner!.isDone) { + while (!_scanner.isDone) { if (state == _ScannerState.html) { scanHtml(asDSX); } else if (state == _ScannerState.freeText) { // Just keep parsing until we hit " b.span!.length.compareTo(a.span!.length)); + potential.sort((a, b) => b.span.length.compareTo(a.span.length)); if (potential.isEmpty) break; var token = potential.first; tokens.add(token); - _scanner!.scan(token.span!.text); + if (token.span.text != null) { + _scanner.scan(token.span.text!); + } if (token.type == TokenType.lt) { brackets.addFirst(token); // Try to see if we are at a tag. - var replay = _scanner!.state; - _scanner!.scan(_whitespace); + var replay = _scanner.state; + _scanner.scan(_whitespace); - if (_scanner!.matches(_id)) { - openTags.addFirst(_scanner!.lastMatch![0]); + if (_scanner.matches(_id)) { + openTags.addFirst(_scanner.lastMatch![0]); } else { - _scanner!.state = replay; + _scanner.state = replay; } } else if (token.type == TokenType.slash) { // Only push if we're at , try to parse text? brackets.removeFirst(); - var replay = _scanner!.state; - _scanner!.scan(_whitespace); + var replay = _scanner.state; + _scanner.scan(_whitespace); - if (!_scanner!.matches('<')) { - _scanner!.state = replay; + if (!_scanner.matches('<')) { + _scanner.state = replay; state = _ScannerState.freeText; break; } @@ -259,7 +268,7 @@ class _Scanner implements Scanner { potential.clear(); } } - } while (brackets.isNotEmpty && !_scanner!.isDone); + } while (brackets.isNotEmpty && !_scanner.isDone); state = _ScannerState.freeText; } diff --git a/packages/jael/jael/pubspec.yaml b/packages/jael/jael/pubspec.yaml index 3b2f9fda..96811e86 100644 --- a/packages/jael/jael/pubspec.yaml +++ b/packages/jael/jael/pubspec.yaml @@ -1,5 +1,5 @@ name: jael -version: 3.0.0 +version: 4.0.0 description: A simple server-side HTML templating engine for Dart. Comparable to Blade or Liquid. author: Tobe O homepage: https://docs.angel-dart.dev/packages/front-end/jael diff --git a/packages/jael/jael/test/render/dsx_test.dart b/packages/jael/jael/test/render/dsx_test.dart index 607e3deb..d018855f 100644 --- a/packages/jael/jael/test/render/dsx_test.dart +++ b/packages/jael/jael/test/render/dsx_test.dart @@ -16,9 +16,9 @@ void main() { expect(foo.getAttribute('bar')?.value?.compute(null), 'baz'); expect( foo - .getAttribute('yes')! - .value! - .compute(SymbolTable(values: {'no': 'maybe'})), + .getAttribute('yes') + ?.value + ?.compute(SymbolTable(values: {'no': 'maybe'})), 'maybe'); }); diff --git a/packages/jael/jael/test/render/render_test.dart b/packages/jael/jael/test/render/render_test.dart index 504a9c2f..79521bf3 100644 --- a/packages/jael/jael/test/render/render_test.dart +++ b/packages/jael/jael/test/render/render_test.dart @@ -3,7 +3,7 @@ import 'package:jael/jael.dart' as jael; import 'package:symbol_table/symbol_table.dart'; import 'package:test/test.dart'; -main() { +void main() { test('attribute binding', () { const template = ''' diff --git a/packages/jael/jael/test/text/common.dart b/packages/jael/jael/test/text/common.dart index fa17e560..7e5fc68e 100644 --- a/packages/jael/jael/test/text/common.dart +++ b/packages/jael/jael/test/text/common.dart @@ -19,6 +19,6 @@ class _IsToken extends Matcher { bool matches(item, Map matchState) { return item is Token && item.type == type && - (text == null || item.span!.text == text); + (text == null || item.span.text == text); } } diff --git a/packages/jael/jael/test/text/scan_test.dart b/packages/jael/jael/test/text/scan_test.dart index a5fad7e6..9541838b 100644 --- a/packages/jael/jael/test/text/scan_test.dart +++ b/packages/jael/jael/test/text/scan_test.dart @@ -3,7 +3,7 @@ import 'package:jael/src/text/scanner.dart'; import 'package:test/test.dart'; import 'common.dart'; -main() { +void main() { test('plain html', () { var tokens = scan('', sourceUrl: 'test.jael').tokens; tokens.forEach(print);