File tree Expand file tree Collapse file tree 9 files changed +108
-1
lines changed Expand file tree Collapse file tree 9 files changed +108
-1
lines changed Original file line number Diff line number Diff line change @@ -538,7 +538,7 @@ module Crystal
538
538
ArrayLiteral HashLiteral RegexLiteral RangeLiteral
539
539
Case StringInterpolation
540
540
MacroExpression MacroIf MacroFor MultiAssign
541
- SizeOf InstanceSizeOf Global Require Select) % }
541
+ SizeOf InstanceSizeOf Global Require Select Assert ) % }
542
542
class {{name.id}}
543
543
include ExpandableNode
544
544
end
Original file line number Diff line number Diff line change @@ -528,6 +528,48 @@ module Crystal
528
528
end
529
529
end
530
530
531
+ def expand (node : Assert )
532
+ transformer = AssertExprTransformer .new(@program )
533
+ (expr = node.expression).transform(visitor)
534
+
535
+ string = [StringLiteral .new(source.inspect).at(node)] of ASTNode
536
+
537
+ transformer.items.each do |assign |
538
+ location = case (val = assign.value)
539
+ when Crystal ::Call
540
+ val.name_column_number
541
+ else
542
+ val.location.column_number
543
+ end - 1
544
+
545
+ string << StringLiteral .new(" " * location + " ^" ).at(node) << assign.value
546
+ end
547
+
548
+ Unless .new(expr,
549
+ Call .new(nil , " raise" ,
550
+ Call .new(Path .global(" AssertionFailed" ), " new" ,
551
+ StringInterpolation .new(string).at(node)
552
+ ).at(node)
553
+ ).at(node)
554
+ ).at(node)
555
+ end
556
+
557
+ class AssertExprTransformer < Transformer
558
+ getter items = [] of Assign
559
+
560
+ def initialize (@program : Program )
561
+ end
562
+
563
+ def transform (node : ASTNode )
564
+ unless node.class.name.ends_with? " Literal"
565
+ if node.location
566
+ items << (node = Assign .new(Var .new(@program .new_temp_var), node))
567
+ end
568
+ end
569
+ node
570
+ end
571
+ end
572
+
531
573
# Transform a multi assign into many assigns.
532
574
def expand (node : MultiAssign )
533
575
# From:
Original file line number Diff line number Diff line change @@ -2662,6 +2662,11 @@ module Crystal
2662
2662
false
2663
2663
end
2664
2664
2665
+ def visit (node : Assert )
2666
+ node.expression.accept self
2667
+ false
2668
+ end
2669
+
2665
2670
def visit (node : MultiAssign )
2666
2671
expand(node)
2667
2672
false
Original file line number Diff line number Diff line change @@ -1150,6 +1150,24 @@ module Crystal
1150
1150
def_equals_and_hash @whens , @else
1151
1151
end
1152
1152
1153
+ class Assert < ASTNode
1154
+ property expression : ASTNode
1155
+ property source : String
1156
+
1157
+ def initialize (@expression , @source )
1158
+ end
1159
+
1160
+ def accept_children (visitor )
1161
+ expression.accept visitor
1162
+ end
1163
+
1164
+ def clone_without_location
1165
+ Assert .new(@expression , @source )
1166
+ end
1167
+
1168
+ def_equals_and_hash @expression
1169
+ end
1170
+
1153
1171
# Node that represents an implicit obj in:
1154
1172
#
1155
1173
# case foo
Original file line number Diff line number Diff line change @@ -700,6 +700,11 @@ module Crystal
700
700
when 'm'
701
701
next_char
702
702
return check_ident_or_keyword(:asm , start)
703
+ when 's'
704
+ next_char
705
+ if next_char == 'e' && next_char == 'r' && next_char == 't'
706
+ return check_ident_or_keyword(:assert , start)
707
+ end
703
708
when '?'
704
709
next_char
705
710
next_char
Original file line number Diff line number Diff line change @@ -1032,6 +1032,8 @@ module Crystal
1032
1032
check_type_declaration { parse_case }
1033
1033
when :select
1034
1034
check_type_declaration { parse_select }
1035
+ when :assert
1036
+ check_type_declaration { parse_assert }
1035
1037
when :if
1036
1038
check_type_declaration { parse_if }
1037
1039
when :ifdef
@@ -2555,6 +2557,17 @@ module Crystal
2555
2557
end
2556
2558
end
2557
2559
2560
+ def parse_assert
2561
+ location = @token .location
2562
+
2563
+ next_token_skip_space
2564
+
2565
+ pos = reader.pos
2566
+ expr = parse_expression
2567
+ source = reader.string[pos...@reader .pos]
2568
+ Assert .new(expr, source).at(location)
2569
+ end
2570
+
2558
2571
def parse_include
2559
2572
parse_include_or_extend Include
2560
2573
end
Original file line number Diff line number Diff line change @@ -1282,6 +1282,13 @@ module Crystal
1282
1282
false
1283
1283
end
1284
1284
1285
+ def visit (node : Assert )
1286
+ @str << keyword(" assert" )
1287
+ @str << " "
1288
+ node.expression.accept self
1289
+ false
1290
+ end
1291
+
1285
1292
def visit (node : ImplicitObj )
1286
1293
false
1287
1294
end
Original file line number Diff line number Diff line change @@ -232,6 +232,16 @@ module Crystal
232
232
node
233
233
end
234
234
235
+ def transform (node : Assert )
236
+ new_expr = node.expression.transform(self )
237
+ unless new_expr == node.expression
238
+ node.expression = new_expr
239
+ node.source = new_expr.to_s
240
+ end
241
+
242
+ node
243
+ end
244
+
235
245
def transform (node : ImplicitObj )
236
246
node
237
247
end
Original file line number Diff line number Diff line change @@ -3328,6 +3328,13 @@ module Crystal
3328
3328
false
3329
3329
end
3330
3330
3331
+ def visit (node : Assert )
3332
+ write_keyword :assert , " "
3333
+ accept node.expression
3334
+
3335
+ false
3336
+ end
3337
+
3331
3338
def visit (node : Attribute )
3332
3339
write_token :"@["
3333
3340
skip_space_or_newline
You can’t perform that action at this time.
0 commit comments