Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2143 gop/parser: ast.DomainTextLit #2144

Merged
merged 2 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,6 @@ func (x *Ident) Pos() token.Pos { return x.NamePos }
// Pos returns position of first character belonging to the node.
func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }

// Pos returns position of first character belonging to the node.
func (x *BasicLit) Pos() token.Pos { return x.ValuePos }

// Pos returns position of first character belonging to the node.
func (x *FuncLit) Pos() token.Pos { return x.Type.Pos() }

Expand Down Expand Up @@ -440,9 +437,6 @@ func (x *Ellipsis) End() token.Pos {
return x.Ellipsis + 3 // len("...")
}

// End returns position of first character immediately after the node.
func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }

// End returns position of first character immediately after the node.
func (x *FuncLit) End() token.Pos { return x.Body.End() }

Expand Down Expand Up @@ -520,7 +514,6 @@ func (x *ChanType) End() token.Pos { return x.Value.End() }
func (*BadExpr) exprNode() {}
func (*Ident) exprNode() {}
func (*Ellipsis) exprNode() {}
func (*BasicLit) exprNode() {}
func (*FuncLit) exprNode() {}
func (*CompositeLit) exprNode() {}
func (*ParenExpr) exprNode() {}
Expand Down
28 changes: 28 additions & 0 deletions ast/ast_gop.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ func (*OverloadFuncDecl) declNode() {}

// -----------------------------------------------------------------------------

// A DomainTextLit node represents a domain text literal.
//
// tpl`...`
type DomainTextLit struct {
Domain *Ident // domain name
ValuePos token.Pos // literal position
Value string // literal string; e.g. `\m\n\o`
Extra *StringLitEx // optional
}

// Pos returns position of first character belonging to the node.
func (x *DomainTextLit) Pos() token.Pos { return x.Domain.NamePos }

// End returns position of first character immediately after the node.
func (x *DomainTextLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }

func (*DomainTextLit) exprNode() {}

// -----------------------------------------------------------------------------

// A BasicLit node represents a literal of basic type.
type BasicLit struct {
ValuePos token.Pos // literal position
Expand All @@ -83,6 +103,14 @@ func NextPartPos(pos token.Pos, part any) (nextPos token.Pos) {
panic("NextPartPos: unexpected parameters")
}

// Pos returns position of first character belonging to the node.
func (x *BasicLit) Pos() token.Pos { return x.ValuePos }

// End returns position of first character immediately after the node.
func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }

func (*BasicLit) exprNode() {}

// -----------------------------------------------------------------------------

// A NumberUnitLit node represents a number with unit.
Expand Down
12 changes: 11 additions & 1 deletion ast/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func Walk(v Visitor, node Node) {
}

// Expressions
case *BadExpr, *Ident:
case *BadExpr, *Ident, *NumberUnitLit:
// nothing to do

case *BasicLit:
Expand All @@ -110,6 +110,16 @@ func Walk(v Visitor, node Node) {
}
}

case *DomainTextLit:
Walk(v, n.Domain)
if n.Extra != nil { // Go+ extended
for _, part := range n.Extra.Parts {
if e, ok := part.(Expr); ok {
Walk(v, e)
}
}
}

case *Ellipsis:
if n.Elt != nil {
Walk(v, n.Elt)
Expand Down
39 changes: 17 additions & 22 deletions demo/gop-parser/gopcalc-2/calc.gop
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,25 @@ func calc(e any) float64 {
case *tpl.Token:
return e.Lit.float!
case []any:
if len(e) == 2 {
if x, ok := e[0].(*tpl.Token); ok && x.Tok == '-' {
return -calc(e[1])
}
x := calc(e[0])
for _, r := range e[1].([]any) {
t := r.([]any)
op := t[0].(*tpl.Token)
y := calc(t[1])
switch op.Tok {
case '+':
x += y
case '-':
x -= y
case '*':
x *= y
case '/':
x /= y
default:
panic("unknown operator")
}
if x, ok := e[0].(*tpl.Token); ok && x.Tok == '-' {
return -calc(e[1])
}
x := calc(e[0])
for r <- e[1].([]any) {
e := r.([]any)
y := calc(e[1])
switch e[0].(*tpl.Token).Tok {
case '+':
x += y
case '-':
x -= y
case '*':
x *= y
case '/':
x /= y
}
return x
}
return x
}
panic("unknown expression")
}
Expand Down
37 changes: 37 additions & 0 deletions parser/_testdata/domaintext/parser.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

file tpl.gop
noEntrypoint
ast.FuncDecl:
Name:
ast.Ident:
Name: main
Type:
ast.FuncType:
Params:
ast.FieldList:
Body:
ast.BlockStmt:
List:
ast.AssignStmt:
Lhs:
ast.Ident:
Name: cl
Tok: :=
Rhs:
ast.ErrWrapExpr:
X:
ast.DomainTextLit:
Domain:
ast.Ident:
Name: tpl
Value: `
expr = termExpr % ("+" | "-")

termExpr = unaryExpr % ("*" | "/")

unaryExpr = operand | "-" unaryExpr

operand = INT | FLOAT | "(" expr ")"
`
Tok: !
9 changes: 9 additions & 0 deletions parser/_testdata/domaintext/tpl.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cl := tpl`
expr = termExpr % ("+" | "-")

termExpr = unaryExpr % ("*" | "/")

unaryExpr = operand | "-" unaryExpr

operand = INT | FLOAT | "(" expr ")"
`!
23 changes: 19 additions & 4 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1718,9 +1718,23 @@

switch p.tok {
case token.IDENT:
x = p.parseIdent()
if !lhs {
p.resolve(x)
ident := p.parseIdent()
if p.tok == token.STRING && p.pos == ident.End() && strings.HasPrefix(p.lit, "`") {
// domain text: tpl`...`
x = &ast.DomainTextLit{
Domain: ident,
ValuePos: p.pos,
Value: p.lit,
}
if debugParseOutput {
log.Printf("ast.DomainTextLit{Domain: %s, Value: %s}\n", ident.Name, p.lit)
}
p.next()
} else {
x = ident
if !lhs {
p.resolve(x)
}
}
return

Expand Down Expand Up @@ -2182,7 +2196,6 @@
case *ast.BadExpr:
case *ast.Ident:
case *ast.BasicLit:
case *ast.NumberUnitLit:
case *ast.FuncLit:
case *ast.CompositeLit:
case *ast.SliceLit:
Expand Down Expand Up @@ -2216,6 +2229,8 @@
x = &ast.BadExpr{From: v.opening, To: v.closing}
case *ast.EnvExpr:
case *ast.ElemEllipsis:
case *ast.NumberUnitLit:
case *ast.DomainTextLit:

Check warning on line 2233 in parser/parser.go

View check run for this annotation

Codecov / codecov/patch

parser/parser.go#L2233

Added line #L2233 was not covered by tests
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression", 3)
Expand Down
4 changes: 4 additions & 0 deletions printer/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,10 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.expr(x.Elt)
p.print(token.ELLIPSIS)

case *ast.DomainTextLit:
p.print(x.Domain)
p.print(&ast.BasicLit{Kind: token.STRING, Value: x.Value})

default:
log.Fatalf("unreachable %T\n", x)
}
Expand Down