diff --git a/runtime/ast/block.go b/runtime/ast/block.go index 2ae8b4671c..1bc64de97f 100644 --- a/runtime/ast/block.go +++ b/runtime/ast/block.go @@ -20,6 +20,8 @@ package ast import ( "encoding/json" + + "github.com/turbolent/prettier" ) type Block struct { @@ -39,6 +41,45 @@ func (b *Block) Walk(walkChild func(Element)) { walkStatements(walkChild, b.Statements) } +var blockStartDoc prettier.Doc = prettier.Text("{") +var blockEndDoc prettier.Doc = prettier.Text("}") +var blockEmptyDoc prettier.Doc = prettier.Text("{}") + +func (b *Block) Doc() prettier.Doc { + if b.IsEmpty() { + return blockEmptyDoc + } + + return prettier.Concat{ + blockStartDoc, + prettier.Indent{ + Doc: StatementsDoc(b.Statements), + }, + prettier.HardLine{}, + blockEndDoc, + } +} + +func StatementsDoc(statements []Statement) prettier.Doc { + var statementsDoc prettier.Concat + + for _, statement := range statements { + // TODO: replace once Statement implements Doc + hasDoc, ok := statement.(interface{ Doc() prettier.Doc }) + if !ok { + continue + } + + statementsDoc = append( + statementsDoc, + prettier.HardLine{}, + hasDoc.Doc(), + ) + } + + return statementsDoc +} + func (b *Block) MarshalJSON() ([]byte, error) { type Alias Block return json.Marshal(&struct { diff --git a/runtime/ast/expression.go b/runtime/ast/expression.go index 120e49f7a6..a73b2ba122 100644 --- a/runtime/ast/expression.go +++ b/runtime/ast/expression.go @@ -45,6 +45,8 @@ type BoolExpression struct { Range } +var _ Expression = &BoolExpression{} + func (*BoolExpression) isExpression() {} func (*BoolExpression) isIfStatementTest() {} @@ -96,6 +98,8 @@ type NilExpression struct { Pos Position `json:"-"` } +var _ Expression = &NilExpression{} + func (*NilExpression) isExpression() {} func (*NilExpression) isIfStatementTest() {} @@ -150,6 +154,8 @@ type StringExpression struct { Range } +var _ Expression = &StringExpression{} + func (*StringExpression) isExpression() {} func (*StringExpression) isIfStatementTest() {} @@ -194,6 +200,8 @@ type IntegerExpression struct { Range } +var _ Expression = &IntegerExpression{} + func (*IntegerExpression) isExpression() {} func (*IntegerExpression) isIfStatementTest() {} @@ -250,6 +258,8 @@ type FixedPointExpression struct { Range } +var _ Expression = &FixedPointExpression{} + func (*FixedPointExpression) isExpression() {} func (*FixedPointExpression) isIfStatementTest() {} @@ -319,6 +329,8 @@ type ArrayExpression struct { Range } +var _ Expression = &ArrayExpression{} + func (*ArrayExpression) isExpression() {} func (*ArrayExpression) isIfStatementTest() {} @@ -386,6 +398,8 @@ type DictionaryExpression struct { Range } +var _ Expression = &DictionaryExpression{} + func (*DictionaryExpression) isExpression() {} func (*DictionaryExpression) isIfStatementTest() {} @@ -492,6 +506,8 @@ type IdentifierExpression struct { Identifier Identifier } +var _ Expression = &IdentifierExpression{} + func (*IdentifierExpression) isExpression() {} func (*IdentifierExpression) isIfStatementTest() {} @@ -564,6 +580,8 @@ type InvocationExpression struct { EndPos Position `json:"-"` } +var _ Expression = &InvocationExpression{} + func (*InvocationExpression) isExpression() {} func (*InvocationExpression) isIfStatementTest() {} @@ -690,6 +708,8 @@ type MemberExpression struct { Identifier Identifier } +var _ Expression = &MemberExpression{} + func (*MemberExpression) isExpression() {} func (*MemberExpression) isIfStatementTest() {} @@ -781,6 +801,8 @@ type IndexExpression struct { Range } +var _ Expression = &IndexExpression{} + func (*IndexExpression) isExpression() {} func (*IndexExpression) isIfStatementTest() {} @@ -841,6 +863,8 @@ type ConditionalExpression struct { Else Expression } +var _ Expression = &ConditionalExpression{} + func (*ConditionalExpression) isExpression() {} func (*ConditionalExpression) isIfStatementTest() {} @@ -934,6 +958,8 @@ type UnaryExpression struct { StartPos Position `json:"-"` } +var _ Expression = &UnaryExpression{} + func (*UnaryExpression) isExpression() {} func (*UnaryExpression) isIfStatementTest() {} @@ -995,6 +1021,8 @@ type BinaryExpression struct { Right Expression } +var _ Expression = &BinaryExpression{} + func (*BinaryExpression) isExpression() {} func (*BinaryExpression) isIfStatementTest() {} @@ -1071,6 +1099,8 @@ type FunctionExpression struct { StartPos Position `json:"-"` } +var _ Expression = &FunctionExpression{} + func (*FunctionExpression) isExpression() {} func (*FunctionExpression) isIfStatementTest() {} @@ -1101,8 +1131,6 @@ var functionExpressionParameterSeparatorDoc prettier.Doc = prettier.Concat{ } var typeSeparatorDoc prettier.Doc = prettier.Text(": ") -var functionExpressionBlockStartDoc prettier.Doc = prettier.Text(" {") -var functionExpressionBlockEndDoc prettier.Doc = prettier.Text("}") var functionExpressionEmptyBlockDoc prettier.Doc = prettier.Text(" {}") func (e *FunctionExpression) Doc() prettier.Doc { @@ -1128,21 +1156,18 @@ func (e *FunctionExpression) Doc() prettier.Doc { if e.FunctionBlock.IsEmpty() { return append(doc, functionExpressionEmptyBlockDoc) - } - - // TODO: pre-conditions - // TODO: post-conditions + } else { + // TODO: pre-conditions + // TODO: post-conditions - statementsDoc := e.statementsDoc() + blockDoc := e.FunctionBlock.Block.Doc() - return append(doc, - functionExpressionBlockStartDoc, - prettier.Indent{ - Doc: statementsDoc, - }, - prettier.HardLine{}, - functionExpressionBlockEndDoc, - ) + return append( + doc, + prettier.Space, + blockDoc, + ) + } } func (e *FunctionExpression) parametersDoc() prettier.Doc { @@ -1165,7 +1190,8 @@ func (e *FunctionExpression) parametersDoc() prettier.Doc { ) } - parameterDoc = append(parameterDoc, + parameterDoc = append( + parameterDoc, prettier.Text(parameter.Identifier.Identifier), typeSeparatorDoc, ) @@ -1184,27 +1210,6 @@ func (e *FunctionExpression) parametersDoc() prettier.Doc { ) } -func (e *FunctionExpression) statementsDoc() prettier.Doc { - var statementsDoc prettier.Concat - - statements := e.FunctionBlock.Block.Statements - - for _, statement := range statements { - // TODO: replace once Statement implements Doc - hasDoc, ok := statement.(interface{ Doc() prettier.Doc }) - if !ok { - continue - } - - statementsDoc = append(statementsDoc, - prettier.HardLine{}, - hasDoc.Doc(), - ) - } - - return statementsDoc -} - func (e *FunctionExpression) StartPosition() Position { return e.StartPos } @@ -1235,6 +1240,8 @@ type CastingExpression struct { ParentVariableDeclaration *VariableDeclaration `json:"-"` } +var _ Expression = &CastingExpression{} + func (*CastingExpression) isExpression() {} func (*CastingExpression) isIfStatementTest() {} @@ -1303,6 +1310,8 @@ type CreateExpression struct { StartPos Position `json:"-"` } +var _ Expression = &CreateExpression{} + func (*CreateExpression) isExpression() {} func (*CreateExpression) isIfStatementTest() {} @@ -1362,6 +1371,8 @@ type DestroyExpression struct { StartPos Position `json:"-"` } +var _ Expression = &DestroyExpression{} + func (*DestroyExpression) isExpression() {} func (*DestroyExpression) isIfStatementTest() {} @@ -1424,6 +1435,8 @@ type ReferenceExpression struct { StartPos Position `json:"-"` } +var _ Expression = &ReferenceExpression{} + func (*ReferenceExpression) isExpression() {} func (*ReferenceExpression) isIfStatementTest() {} @@ -1498,6 +1511,8 @@ type ForceExpression struct { EndPos Position `json:"-"` } +var _ Expression = &ForceExpression{} + func (*ForceExpression) isExpression() {} func (*ForceExpression) isIfStatementTest() {} @@ -1557,6 +1572,8 @@ type PathExpression struct { Identifier Identifier } +var _ Expression = &PathExpression{} + func (*PathExpression) isExpression() {} func (*PathExpression) isIfStatementTest() {} diff --git a/runtime/ast/expression_test.go b/runtime/ast/expression_test.go index 76266dfd59..272962487b 100644 --- a/runtime/ast/expression_test.go +++ b/runtime/ast/expression_test.go @@ -2045,18 +2045,21 @@ func TestFunctionExpression_Doc(t *testing.T) { // TODO: type }, }, - prettier.Text(" {"), - prettier.Indent{ - Doc: prettier.Concat{ - prettier.HardLine{}, - prettier.Concat{ - prettier.Text("return "), - prettier.Text("1"), + prettier.Text(" "), + prettier.Concat{ + prettier.Text("{"), + prettier.Indent{ + Doc: prettier.Concat{ + prettier.HardLine{}, + prettier.Concat{ + prettier.Text("return "), + prettier.Text("1"), + }, }, }, + prettier.HardLine{}, + prettier.Text("}"), }, - prettier.HardLine{}, - prettier.Text("}"), } assert.Equal(t, expected, expr.Doc()) diff --git a/runtime/ast/statement.go b/runtime/ast/statement.go index 4e179af5f6..f1d3418c7b 100644 --- a/runtime/ast/statement.go +++ b/runtime/ast/statement.go @@ -36,6 +36,8 @@ type ReturnStatement struct { Range } +var _ Statement = &ReturnStatement{} + func (*ReturnStatement) isStatement() {} func (s *ReturnStatement) Accept(visitor Visitor) Repr { @@ -80,6 +82,8 @@ type BreakStatement struct { Range } +var _ Statement = &BreakStatement{} + func (*BreakStatement) isStatement() {} func (s *BreakStatement) Accept(visitor Visitor) Repr { @@ -90,6 +94,12 @@ func (*BreakStatement) Walk(_ func(Element)) { // NO-OP } +const breakStatementKeywordDoc = prettier.Text("break") + +func (*BreakStatement) Doc() prettier.Doc { + return breakStatementKeywordDoc +} + func (s *BreakStatement) MarshalJSON() ([]byte, error) { type Alias BreakStatement return json.Marshal(&struct { @@ -107,6 +117,8 @@ type ContinueStatement struct { Range } +var _ Statement = &ContinueStatement{} + func (*ContinueStatement) isStatement() {} func (s *ContinueStatement) Accept(visitor Visitor) Repr { @@ -117,6 +129,12 @@ func (*ContinueStatement) Walk(_ func(Element)) { // NO-OP } +const continueStatementKeywordDoc = prettier.Text("continue") + +func (*ContinueStatement) Doc() prettier.Doc { + return continueStatementKeywordDoc +} + func (s *ContinueStatement) MarshalJSON() ([]byte, error) { type Alias ContinueStatement return json.Marshal(&struct { @@ -144,6 +162,10 @@ type IfStatement struct { StartPos Position `json:"-"` } +var _ Statement = &IfStatement{} + +func (*IfStatement) isStatement() {} + func (s *IfStatement) StartPosition() Position { return s.StartPos } @@ -155,8 +177,6 @@ func (s *IfStatement) EndPosition() Position { return s.Then.EndPosition() } -func (*IfStatement) isStatement() {} - func (s *IfStatement) Accept(visitor Visitor) Repr { return visitor.VisitIfStatement(s) } @@ -169,6 +189,49 @@ func (s *IfStatement) Walk(walkChild func(Element)) { } } +const ifStatementIfKeywordSpaceDoc = prettier.Text("if ") +const ifStatementSpaceElseKeywordSpaceDoc = prettier.Text(" else ") + +func (s *IfStatement) Doc() prettier.Doc { + var testDoc prettier.Doc + // TODO: replace once IfStatementTest implements Doc + testWithDoc, ok := s.Test.(interface{ Doc() prettier.Doc }) + if ok { + testDoc = testWithDoc.Doc() + } + + doc := prettier.Concat{ + ifStatementIfKeywordSpaceDoc, + testDoc, + prettier.Space, + s.Then.Doc(), + } + + if s.Else != nil { + var elseDoc prettier.Doc + if len(s.Else.Statements) == 1 { + if elseIfStatement, ok := s.Else.Statements[0].(*IfStatement); ok { + elseDoc = elseIfStatement.Doc() + } + } + if elseDoc == nil { + elseDoc = s.Else.Doc() + } + + doc = append( + doc, + ifStatementSpaceElseKeywordSpaceDoc, + prettier.Group{ + Doc: elseDoc, + }, + ) + } + + return prettier.Group{ + Doc: doc, + } +} + func (s *IfStatement) MarshalJSON() ([]byte, error) { type Alias IfStatement return json.Marshal(&struct { @@ -190,6 +253,8 @@ type WhileStatement struct { StartPos Position `json:"-"` } +var _ Statement = &WhileStatement{} + func (*WhileStatement) isStatement() {} func (s *WhileStatement) Accept(visitor Visitor) Repr { @@ -209,6 +274,19 @@ func (s *WhileStatement) EndPosition() Position { return s.Block.EndPosition() } +const whileStatementKeywordSpaceDoc = prettier.Text("while ") + +func (s *WhileStatement) Doc() prettier.Doc { + return prettier.Group{ + Doc: prettier.Concat{ + whileStatementKeywordSpaceDoc, + s.Test.Doc(), + prettier.Space, + s.Block.Doc(), + }, + } +} + func (s *WhileStatement) MarshalJSON() ([]byte, error) { type Alias WhileStatement return json.Marshal(&struct { @@ -232,6 +310,8 @@ type ForStatement struct { StartPos Position `json:"-"` } +var _ Statement = &ForStatement{} + func (*ForStatement) isStatement() {} func (s *ForStatement) Accept(visitor Visitor) Repr { @@ -251,6 +331,36 @@ func (s *ForStatement) EndPosition() Position { return s.Block.EndPosition() } +const forStatementForKeywordSpaceDoc = prettier.Text("for ") +const forStatementSpaceInKeywordSpaceDoc = prettier.Text(" in ") + +func (s *ForStatement) Doc() prettier.Doc { + doc := prettier.Concat{ + forStatementForKeywordSpaceDoc, + } + + if s.Index != nil { + doc = append( + doc, + prettier.Text(s.Index.Identifier), + prettier.Text(", "), + ) + } + + doc = append( + doc, + prettier.Text(s.Identifier.Identifier), + forStatementSpaceInKeywordSpaceDoc, + s.Value.Doc(), + prettier.Space, + s.Block.Doc(), + ) + + return prettier.Group{ + Doc: doc, + } +} + func (s *ForStatement) MarshalJSON() ([]byte, error) { type Alias ForStatement return json.Marshal(&struct { @@ -271,6 +381,10 @@ type EmitStatement struct { StartPos Position `json:"-"` } +var _ Statement = &EmitStatement{} + +func (*EmitStatement) isStatement() {} + func (s *EmitStatement) StartPosition() Position { return s.StartPos } @@ -279,8 +393,6 @@ func (s *EmitStatement) EndPosition() Position { return s.InvocationExpression.EndPosition() } -func (*EmitStatement) isStatement() {} - func (s *EmitStatement) Accept(visitor Visitor) Repr { return visitor.VisitEmitStatement(s) } @@ -289,6 +401,16 @@ func (s *EmitStatement) Walk(walkChild func(Element)) { walkChild(s.InvocationExpression) } +const emitStatementKeywordSpaceDoc = prettier.Text("emit ") + +func (s *EmitStatement) Doc() prettier.Doc { + return prettier.Concat{ + emitStatementKeywordSpaceDoc, + // TODO: potentially parenthesize + s.InvocationExpression.Doc(), + } +} + func (s *EmitStatement) MarshalJSON() ([]byte, error) { type Alias EmitStatement return json.Marshal(&struct { @@ -310,6 +432,14 @@ type AssignmentStatement struct { Value Expression } +var _ Statement = &AssignmentStatement{} + +func (*AssignmentStatement) isStatement() {} + +func (s *AssignmentStatement) Accept(visitor Visitor) Repr { + return visitor.VisitAssignmentStatement(s) +} + func (s *AssignmentStatement) StartPosition() Position { return s.Target.StartPosition() } @@ -318,17 +448,27 @@ func (s *AssignmentStatement) EndPosition() Position { return s.Value.EndPosition() } -func (*AssignmentStatement) isStatement() {} - -func (s *AssignmentStatement) Accept(visitor Visitor) Repr { - return visitor.VisitAssignmentStatement(s) -} - func (s *AssignmentStatement) Walk(walkChild func(Element)) { walkChild(s.Target) walkChild(s.Value) } +func (s *AssignmentStatement) Doc() prettier.Doc { + return prettier.Group{ + Doc: prettier.Concat{ + s.Target.Doc(), + prettier.Space, + s.Transfer.Doc(), + prettier.Space, + prettier.Group{ + Doc: prettier.Indent{ + Doc: s.Value.Doc(), + }, + }, + }, + } +} + func (s *AssignmentStatement) MarshalJSON() ([]byte, error) { type Alias AssignmentStatement return json.Marshal(&struct { @@ -349,6 +489,10 @@ type SwapStatement struct { Right Expression } +var _ Statement = &SwapStatement{} + +func (*SwapStatement) isStatement() {} + func (s *SwapStatement) StartPosition() Position { return s.Left.StartPosition() } @@ -357,8 +501,6 @@ func (s *SwapStatement) EndPosition() Position { return s.Right.EndPosition() } -func (*SwapStatement) isStatement() {} - func (s *SwapStatement) Accept(visitor Visitor) Repr { return visitor.VisitSwapStatement(s) } @@ -368,6 +510,18 @@ func (s *SwapStatement) Walk(walkChild func(Element)) { walkChild(s.Right) } +const swapStatementSpaceSymbolSpaceDoc = prettier.Text(" <-> ") + +func (s *SwapStatement) Doc() prettier.Doc { + return prettier.Group{ + Doc: prettier.Concat{ + s.Left.Doc(), + swapStatementSpaceSymbolSpaceDoc, + s.Right.Doc(), + }, + } +} + func (s *SwapStatement) MarshalJSON() ([]byte, error) { type Alias SwapStatement return json.Marshal(&struct { @@ -387,6 +541,10 @@ type ExpressionStatement struct { Expression Expression } +var _ Statement = &ExpressionStatement{} + +func (*ExpressionStatement) isStatement() {} + func (s *ExpressionStatement) StartPosition() Position { return s.Expression.StartPosition() } @@ -395,8 +553,6 @@ func (s *ExpressionStatement) EndPosition() Position { return s.Expression.EndPosition() } -func (*ExpressionStatement) isStatement() {} - func (s *ExpressionStatement) Accept(visitor Visitor) Repr { return visitor.VisitExpressionStatement(s) } @@ -405,6 +561,10 @@ func (s *ExpressionStatement) Walk(walkChild func(Element)) { walkChild(s.Expression) } +func (s *ExpressionStatement) Doc() prettier.Doc { + return s.Expression.Doc() +} + func (s *ExpressionStatement) MarshalJSON() ([]byte, error) { type Alias ExpressionStatement return json.Marshal(&struct { @@ -426,6 +586,8 @@ type SwitchStatement struct { Range } +var _ Statement = &SwitchStatement{} + func (*SwitchStatement) isStatement() {} func (s *SwitchStatement) Accept(visitor Visitor) Repr { @@ -440,6 +602,42 @@ func (s *SwitchStatement) Walk(walkChild func(Element)) { } } +const switchStatementKeywordSpaceDoc = prettier.Text("switch ") + +func (s *SwitchStatement) Doc() prettier.Doc { + + bodyDoc := make(prettier.Concat, 0, len(s.Cases)) + + for _, switchCase := range s.Cases { + bodyDoc = append( + bodyDoc, + prettier.HardLine{}, + switchCase.Doc(), + ) + } + + return prettier.Concat{ + prettier.Group{ + Doc: prettier.Concat{ + switchStatementKeywordSpaceDoc, + prettier.Indent{ + Doc: prettier.Concat{ + prettier.SoftLine{}, + s.Expression.Doc(), + }, + }, + prettier.Line{}, + }, + }, + blockStartDoc, + prettier.Indent{ + Doc: bodyDoc, + }, + prettier.HardLine{}, + blockEndDoc, + } +} + func (s *SwitchStatement) MarshalJSON() ([]byte, error) { type Alias SwitchStatement return json.Marshal(&struct { @@ -469,3 +667,27 @@ func (s *SwitchCase) MarshalJSON() ([]byte, error) { Alias: (*Alias)(s), }) } + +const switchCaseKeywordSpaceDoc = prettier.Text("case ") +const switchCaseColonSymbolDoc = prettier.Text(":") +const switchCaseDefaultKeywordSpaceDoc = prettier.Text("default:") + +func (s *SwitchCase) Doc() prettier.Doc { + statementsDoc := prettier.Indent{ + Doc: StatementsDoc(s.Statements), + } + + if s.Expression == nil { + return prettier.Concat{ + switchCaseDefaultKeywordSpaceDoc, + statementsDoc, + } + } + + return prettier.Concat{ + switchCaseKeywordSpaceDoc, + s.Expression.Doc(), + switchCaseColonSymbolDoc, + statementsDoc, + } +} diff --git a/runtime/ast/statement_test.go b/runtime/ast/statement_test.go index 9671b0dd1d..f503cc3898 100644 --- a/runtime/ast/statement_test.go +++ b/runtime/ast/statement_test.go @@ -62,6 +62,22 @@ func TestExpressionStatement_MarshalJSON(t *testing.T) { ) } +func TestExpressionStatement_Doc(t *testing.T) { + + t.Parallel() + + stmt := &ExpressionStatement{ + Expression: &BoolExpression{ + Value: false, + }, + } + + assert.Equal(t, + prettier.Text("false"), + stmt.Doc(), + ) +} + func TestReturnStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -100,6 +116,7 @@ func TestReturnStatement_MarshalJSON(t *testing.T) { string(actual), ) } + func TestReturnStatement_Doc(t *testing.T) { t.Parallel() @@ -162,6 +179,16 @@ func TestBreakStatement_MarshalJSON(t *testing.T) { ) } +func TestBreakStatement_Doc(t *testing.T) { + + t.Parallel() + + assert.Equal(t, + prettier.Text("break"), + (&BreakStatement{}).Doc(), + ) +} + func TestContinueStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -188,6 +215,16 @@ func TestContinueStatement_MarshalJSON(t *testing.T) { ) } +func TestContinueStatement_Doc(t *testing.T) { + + t.Parallel() + + assert.Equal(t, + prettier.Text("continue"), + (&ContinueStatement{}).Doc(), + ) +} + func TestIfStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -250,6 +287,93 @@ func TestIfStatement_MarshalJSON(t *testing.T) { ) } +func TestIfStatement_Doc(t *testing.T) { + + t.Parallel() + + t.Run("empty if-else", func(t *testing.T) { + + t.Parallel() + + stmt := &IfStatement{ + Test: &BoolExpression{ + Value: false, + }, + Then: &Block{ + Statements: []Statement{}, + }, + Else: &Block{ + Statements: []Statement{}, + }, + } + + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("if "), + prettier.Text("false"), + prettier.Text(" "), + prettier.Text("{}"), + prettier.Text(" else "), + prettier.Group{ + Doc: prettier.Text("{}"), + }, + }, + }, + stmt.Doc(), + ) + }) + + t.Run("if-else if", func(t *testing.T) { + + t.Parallel() + + stmt := &IfStatement{ + Test: &BoolExpression{ + Value: false, + }, + Then: &Block{ + Statements: []Statement{}, + }, + Else: &Block{ + Statements: []Statement{ + &IfStatement{ + Test: &BoolExpression{ + Value: true, + }, + Then: &Block{ + Statements: []Statement{}, + }, + }, + }, + }, + } + + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("if "), + prettier.Text("false"), + prettier.Text(" "), + prettier.Text("{}"), + prettier.Text(" else "), + prettier.Group{ + Doc: prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("if "), + prettier.Text("true"), + prettier.Text(" "), + prettier.Text("{}"), + }, + }, + }, + }, + }, + stmt.Doc(), + ) + }) +} + func TestWhileStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -299,65 +423,247 @@ func TestWhileStatement_MarshalJSON(t *testing.T) { ) } -func TestForStatement_MarshalJSON(t *testing.T) { +func TestWhileStatement_Doc(t *testing.T) { t.Parallel() - stmt := &ForStatement{ - Identifier: Identifier{ - Identifier: "foobar", - Pos: Position{Offset: 1, Line: 2, Column: 3}, - }, - Value: &BoolExpression{ + stmt := &WhileStatement{ + Test: &BoolExpression{ Value: false, - Range: Range{ - StartPos: Position{Offset: 4, Line: 5, Column: 6}, - EndPos: Position{Offset: 7, Line: 8, Column: 9}, - }, }, Block: &Block{ Statements: []Statement{}, - Range: Range{ - StartPos: Position{Offset: 10, Line: 11, Column: 12}, - EndPos: Position{Offset: 13, Line: 14, Column: 15}, - }, }, - StartPos: Position{Offset: 16, Line: 17, Column: 18}, } - actual, err := json.Marshal(stmt) - require.NoError(t, err) - - assert.JSONEq(t, - ` - { - "Type": "ForStatement", - "Identifier": { - "Identifier": "foobar", - "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, - "EndPos": {"Offset": 6, "Line": 2, "Column": 8} - }, - "Index": null, - "Value": { - "Type": "BoolExpression", - "Value": false, - "StartPos": {"Offset": 4, "Line": 5, "Column": 6}, - "EndPos": {"Offset": 7, "Line": 8, "Column": 9} - }, - "Block": { - "Type": "Block", - "Statements": [], - "StartPos": {"Offset": 10, "Line": 11, "Column": 12}, - "EndPos": {"Offset": 13, "Line": 14, "Column": 15} - }, - "StartPos": {"Offset": 16, "Line": 17, "Column": 18}, - "EndPos": {"Offset": 13, "Line": 14, "Column": 15} - } - `, - string(actual), + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("while "), + prettier.Text("false"), + prettier.Text(" "), + prettier.Text("{}"), + }, + }, + stmt.Doc(), ) } +func TestForStatement_MarshalJSON(t *testing.T) { + + t.Parallel() + + t.Run("without index", func(t *testing.T) { + + t.Parallel() + + stmt := &ForStatement{ + Identifier: Identifier{ + Identifier: "foobar", + Pos: Position{Offset: 1, Line: 2, Column: 3}, + }, + Value: &BoolExpression{ + Value: false, + Range: Range{ + StartPos: Position{Offset: 4, Line: 5, Column: 6}, + EndPos: Position{Offset: 7, Line: 8, Column: 9}, + }, + }, + Block: &Block{ + Statements: []Statement{}, + Range: Range{ + StartPos: Position{Offset: 10, Line: 11, Column: 12}, + EndPos: Position{Offset: 13, Line: 14, Column: 15}, + }, + }, + StartPos: Position{Offset: 16, Line: 17, Column: 18}, + } + + actual, err := json.Marshal(stmt) + require.NoError(t, err) + + assert.JSONEq(t, + ` + { + "Type": "ForStatement", + "Identifier": { + "Identifier": "foobar", + "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, + "EndPos": {"Offset": 6, "Line": 2, "Column": 8} + }, + "Index": null, + "Value": { + "Type": "BoolExpression", + "Value": false, + "StartPos": {"Offset": 4, "Line": 5, "Column": 6}, + "EndPos": {"Offset": 7, "Line": 8, "Column": 9} + }, + "Block": { + "Type": "Block", + "Statements": [], + "StartPos": {"Offset": 10, "Line": 11, "Column": 12}, + "EndPos": {"Offset": 13, "Line": 14, "Column": 15} + }, + "StartPos": {"Offset": 16, "Line": 17, "Column": 18}, + "EndPos": {"Offset": 13, "Line": 14, "Column": 15} + } + `, + string(actual), + ) + }) + + t.Run("with index", func(t *testing.T) { + + t.Parallel() + + stmt := &ForStatement{ + Index: &Identifier{ + Identifier: "i", + Pos: Position{Offset: 1, Line: 2, Column: 3}, + }, + Identifier: Identifier{ + Identifier: "foobar", + Pos: Position{Offset: 4, Line: 5, Column: 6}, + }, + Value: &BoolExpression{ + Value: false, + Range: Range{ + StartPos: Position{Offset: 7, Line: 8, Column: 9}, + EndPos: Position{Offset: 10, Line: 11, Column: 12}, + }, + }, + Block: &Block{ + Statements: []Statement{}, + Range: Range{ + StartPos: Position{Offset: 13, Line: 14, Column: 15}, + EndPos: Position{Offset: 16, Line: 17, Column: 18}, + }, + }, + StartPos: Position{Offset: 19, Line: 20, Column: 21}, + } + + actual, err := json.Marshal(stmt) + require.NoError(t, err) + + assert.JSONEq(t, + ` + { + "Type": "ForStatement", + "Index": { + "Identifier": "i", + "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, + "EndPos": {"Offset": 1, "Line": 2, "Column": 3} + }, + "Identifier": { + "Identifier": "foobar", + "StartPos": {"Offset": 4, "Line": 5, "Column": 6}, + "EndPos": {"Offset": 9, "Line": 5, "Column": 11} + }, + "Value": { + "Type": "BoolExpression", + "Value": false, + "StartPos": {"Offset": 7, "Line": 8, "Column": 9}, + "EndPos": {"Offset": 10, "Line": 11, "Column": 12} + }, + "Block": { + "Type": "Block", + "Statements": [], + "StartPos":{"Offset": 13, "Line": 14, "Column": 15}, + "EndPos": {"Offset": 16, "Line": 17, "Column": 18} + }, + "StartPos": {"Offset": 19, "Line": 20, "Column": 21}, + "EndPos": {"Offset": 16, "Line": 17, "Column": 18} + } + `, + string(actual), + ) + }) + +} + +func TestForStatement_Doc(t *testing.T) { + + t.Parallel() + + t.Run("without index", func(t *testing.T) { + + t.Parallel() + + stmt := &ForStatement{ + Identifier: Identifier{ + Identifier: "foobar", + }, + Value: &BoolExpression{ + Value: false, + }, + Block: &Block{ + Statements: []Statement{}, + }, + } + + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("for "), + prettier.Text("foobar"), + prettier.Text(" in "), + prettier.Text("false"), + prettier.Text(" "), + prettier.Text("{}"), + }, + }, + stmt.Doc(), + ) + }) + + t.Run("with index", func(t *testing.T) { + + t.Parallel() + + stmt := &ForStatement{ + Index: &Identifier{ + Identifier: "i", + Pos: Position{Offset: 1, Line: 2, Column: 3}, + }, + Identifier: Identifier{ + Identifier: "foobar", + Pos: Position{Offset: 4, Line: 5, Column: 6}, + }, + Value: &BoolExpression{ + Value: false, + Range: Range{ + StartPos: Position{Offset: 7, Line: 8, Column: 9}, + EndPos: Position{Offset: 10, Line: 11, Column: 12}, + }, + }, + Block: &Block{ + Statements: []Statement{}, + Range: Range{ + StartPos: Position{Offset: 13, Line: 14, Column: 15}, + EndPos: Position{Offset: 16, Line: 17, Column: 18}, + }, + }, + StartPos: Position{Offset: 19, Line: 20, Column: 21}, + } + + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("for "), + prettier.Text("i"), + prettier.Text(", "), + prettier.Text("foobar"), + prettier.Text(" in "), + prettier.Text("false"), + prettier.Text(" "), + prettier.Text("{}"), + }, + }, + stmt.Doc(), + ) + }) +} + func TestAssignmentStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -419,6 +725,42 @@ func TestAssignmentStatement_MarshalJSON(t *testing.T) { ) } +func TestAssignmentStatement_Doc(t *testing.T) { + + t.Parallel() + + stmt := &AssignmentStatement{ + Target: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "foobar", + }, + }, + Transfer: &Transfer{ + Operation: TransferOperationCopy, + }, + Value: &BoolExpression{ + Value: false, + }, + } + + require.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("foobar"), + prettier.Text(" "), + prettier.Text("="), + prettier.Text(" "), + prettier.Group{ + Doc: prettier.Indent{ + Doc: prettier.Text("false"), + }, + }, + }, + }, + stmt.Doc(), + ) +} + func TestSwapStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -470,6 +812,33 @@ func TestSwapStatement_MarshalJSON(t *testing.T) { ) } +func TestSwapStatement_Doc(t *testing.T) { + + t.Parallel() + + stmt := &SwapStatement{ + Left: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "foobar", + }, + }, + Right: &BoolExpression{ + Value: false, + }, + } + + assert.Equal(t, + prettier.Group{ + Doc: prettier.Concat{ + prettier.Text("foobar"), + swapStatementSpaceSymbolSpaceDoc, + prettier.Text("false"), + }, + }, + stmt.Doc(), + ) +} + func TestEmitStatement_MarshalJSON(t *testing.T) { t.Parallel() @@ -578,3 +947,252 @@ func TestEmitStatement_MarshalJSON(t *testing.T) { string(actual), ) } + +func TestEmitStatement_Doc(t *testing.T) { + + t.Parallel() + + stmt := &EmitStatement{ + InvocationExpression: &InvocationExpression{ + InvokedExpression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "foobar", + }, + }, + }, + } + + require.Equal(t, + prettier.Concat{ + prettier.Text("emit "), + prettier.Concat{ + prettier.Text("foobar"), + prettier.Text("()"), + }, + }, + stmt.Doc(), + ) +} + +func TestSwitchStatement_MarshalJSON(t *testing.T) { + + t.Parallel() + + stmt := &SwitchStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "foo", + Pos: Position{Offset: 1, Line: 2, Column: 3}, + }, + }, + Cases: []*SwitchCase{ + { + Expression: &BoolExpression{ + Value: false, + Range: Range{ + StartPos: Position{Offset: 4, Line: 5, Column: 6}, + EndPos: Position{Offset: 7, Line: 8, Column: 9}, + }, + }, + Statements: []Statement{ + &ExpressionStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "bar", + Pos: Position{Offset: 10, Line: 11, Column: 12}, + }, + }, + }, + }, + Range: Range{ + StartPos: Position{Offset: 13, Line: 14, Column: 15}, + EndPos: Position{Offset: 16, Line: 17, Column: 18}, + }, + }, + { + Statements: []Statement{ + &ExpressionStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "baz", + Pos: Position{Offset: 19, Line: 20, Column: 21}, + }, + }, + }, + }, + Range: Range{ + StartPos: Position{Offset: 22, Line: 23, Column: 24}, + EndPos: Position{Offset: 25, Line: 26, Column: 27}, + }, + }, + }, + Range: Range{ + StartPos: Position{Offset: 28, Line: 29, Column: 30}, + EndPos: Position{Offset: 31, Line: 32, Column: 33}, + }, + } + + actual, err := json.Marshal(stmt) + require.NoError(t, err) + + assert.JSONEq(t, + ` + { + "Type": "SwitchStatement", + "Expression": { + "Type": "IdentifierExpression", + "Identifier": { + "Identifier": "foo", + "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, + "EndPos": {"Offset": 3, "Line": 2, "Column": 5} + }, + "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, + "EndPos": {"Offset": 3, "Line": 2, "Column": 5} + }, + "Cases": [ + { + "Type": "SwitchCase", + "Expression": { + "Type": "BoolExpression", + "Value": false, + "StartPos": {"Offset": 4, "Line": 5, "Column": 6}, + "EndPos": {"Offset": 7, "Line": 8, "Column": 9} + }, + "Statements": [ + { + "Type": "ExpressionStatement", + "StartPos": {"Offset": 10, "Line": 11, "Column": 12}, + "EndPos": {"Offset": 12, "Line": 11, "Column": 14}, + "Expression": { + "Type": "IdentifierExpression", + "Identifier": { + "Identifier": "bar", + "StartPos": {"Offset": 10, "Line": 11, "Column": 12}, + "EndPos": {"Offset": 12, "Line": 11, "Column": 14} + }, + "StartPos": {"Offset": 10, "Line": 11, "Column": 12}, + "EndPos": {"Offset": 12, "Line": 11, "Column": 14} + } + } + ], + "StartPos": {"Offset": 13, "Line": 14, "Column": 15}, + "EndPos": {"Offset": 16, "Line": 17, "Column": 18} + }, + { + "Type": "SwitchCase", + "Expression": null, + "Statements": [ + { + "Type": "ExpressionStatement", + "StartPos": {"Offset": 19, "Line": 20, "Column": 21}, + "EndPos": {"Offset": 21, "Line": 20, "Column": 23}, + "Expression": { + "Type": "IdentifierExpression", + "Identifier": { + "Identifier": "baz", + "StartPos": {"Offset": 19, "Line": 20, "Column": 21}, + "EndPos": {"Offset": 21, "Line": 20, "Column": 23} + }, + "StartPos": {"Offset": 19, "Line": 20, "Column": 21}, + "EndPos": {"Offset": 21, "Line": 20, "Column": 23} + } + } + ], + "StartPos": {"Offset": 22, "Line": 23, "Column": 24}, + "EndPos": {"Offset": 25, "Line": 26, "Column": 27} + } + ], + "StartPos": {"Offset": 28, "Line": 29, "Column": 30}, + "EndPos": {"Offset": 31, "Line": 32, "Column": 33} + } + `, + string(actual), + ) +} + +func TestSwitchStatement_Doc(t *testing.T) { + + t.Parallel() + + stmt := &SwitchStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "foo", + }, + }, + Cases: []*SwitchCase{ + { + Expression: &BoolExpression{ + Value: false, + }, + Statements: []Statement{ + &ExpressionStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "bar", + }, + }, + }, + }, + }, + { + Statements: []Statement{ + &ExpressionStatement{ + Expression: &IdentifierExpression{ + Identifier: Identifier{ + Identifier: "baz", + }, + }, + }, + }, + }, + }, + } + + assert.Equal(t, + prettier.Concat{ + prettier.Group{ + Doc: prettier.Concat{ + switchStatementKeywordSpaceDoc, + prettier.Indent{ + Doc: prettier.Concat{ + prettier.SoftLine{}, + prettier.Text("foo"), + }, + }, + prettier.Line{}, + }, + }, + prettier.Text("{"), + prettier.Indent{ + Doc: prettier.Concat{ + prettier.HardLine{}, + prettier.Concat{ + switchCaseKeywordSpaceDoc, + prettier.Text("false"), + switchCaseColonSymbolDoc, + prettier.Indent{ + Doc: prettier.Concat{ + prettier.HardLine{}, + prettier.Text("bar"), + }, + }, + }, + prettier.HardLine{}, + prettier.Concat{ + switchCaseDefaultKeywordSpaceDoc, + prettier.Indent{ + Doc: prettier.Concat{ + prettier.HardLine{}, + prettier.Text("baz"), + }, + }, + }, + }, + }, + prettier.HardLine{}, + prettier.Text("}"), + }, + stmt.Doc(), + ) +} diff --git a/tools/pretty/main.go b/tools/pretty/main.go index 52bce31204..3cf1c7dea0 100644 --- a/tools/pretty/main.go +++ b/tools/pretty/main.go @@ -110,7 +110,7 @@ const page = ` - +