Skip to content

Commit

Permalink
Get rid of awkward noProps construct
Browse files Browse the repository at this point in the history
  • Loading branch information
marijnh committed Oct 20, 2020
1 parent 95db013 commit 61045f7
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 22 deletions.
19 changes: 8 additions & 11 deletions src/build.ts
Expand Up @@ -4,7 +4,7 @@ import {GrammarDeclaration, RuleDeclaration, TokenDeclaration, ExternalTokenDecl
ChoiceExpression, RepeatExpression, SetExpression, AnyExpression, ConflictMarker,
InlineRuleExpression, SpecializeExpression, Prop, PropPart,
exprsEq, exprEq} from "./node"
import {Term, TermSet, Rule, Conflicts, Props, noProps} from "./grammar"
import {Term, TermSet, Rule, Conflicts, Props, hasProps} from "./grammar"
import {State, MAX_CHAR, Conflict} from "./token"
import {Input} from "./parse"
import {computeFirstSets, buildFullAutomaton, finishAutomaton, State as LRState, Shift, Reduce, Pos} from "./automaton"
Expand Down Expand Up @@ -232,7 +232,7 @@ class Builder {
this.namespaces[name] = value
}

newName(base: string, nodeName: string | null | true = null, props: Props = noProps): Term {
newName(base: string, nodeName: string | null | true = null, props: Props = {}): Term {
for (let i = nodeName ? 0 : 1;; i++) {
let name = i ? `${base}-${i}` : base
if (!this.terms.names[name])
Expand Down Expand Up @@ -891,7 +891,7 @@ ${encodeArray(spec.end.compile().toArray({}, none))}, ${spec.placeholder.id}]`
dynamicPrec: number,
inline: boolean
} {
let result = noProps, name = defaultName && !ignored(defaultName) && !/ /.test(defaultName) ? defaultName : null
let result: Props = {}, name = defaultName && !ignored(defaultName) && !/ /.test(defaultName) ? defaultName : null
let dialect = null, dynamicPrec = 0, inline = false
for (let prop of props) {
if (prop.name == "name") {
Expand All @@ -918,24 +918,22 @@ ${encodeArray(spec.end.compile().toArray({}, none))}, ${spec.placeholder.id}]`
} else if (!this.knownProps[prop.name]) {
this.raise(`Unknown prop name '${prop.name}'`, prop.start)
} else {
if (result == noProps) result = Object.create(null)
result[prop.name] = this.finishProp(prop, args, params)
}
}
if (expr && this.ast.autoDelim && (name || result != noProps)) {
if (expr && this.ast.autoDelim && (name || hasProps(result))) {
let delim = this.findDelimiters(expr)
if (delim) {
addToProp(delim[0], "closedBy", delim[1].nodeName!)
addToProp(delim[1], "openedBy", delim[0].nodeName!)
}
}
if (defaultProps && defaultProps != noProps) {
if (result == noProps) result = Object.create(null)
if (defaultProps && hasProps(defaultProps)) {
for (let prop in defaultProps) if (!(prop in result)) result[prop] = defaultProps[prop]
}
if (result != noProps && !name && !result.top)
if (hasProps(result) && !name && !result.top)
this.raise(`Node has properties but no name`, props.length ? props[0].start : expr!.start)
if (inline && (result != noProps || dialect || dynamicPrec))
if (inline && (hasProps(result) || dialect || dynamicPrec))
this.raise(`Inline nodes can't have props, dynamic precedence, or a dialect`, props[0].start)
if (inline && name) name = null
return {name, props: result, dialect, dynamicPrec, inline}
Expand Down Expand Up @@ -1132,7 +1130,6 @@ class FinishStateContext {
}

function addToProp(term: Term, prop: string, value: string) {
if (term.props == noProps) term.props = Object.create(null)
let cur = term.props[prop]
if (!cur || cur.split(" ").indexOf(value) < 0) term.props[prop] = cur ? cur + " " + value : value
}
Expand Down Expand Up @@ -1378,7 +1375,7 @@ class TokenSet {
getLiteral(expr: LiteralExpression) {
let id = JSON.stringify(expr.value)
for (let built of this.built) if (built.id == id) return built.term
let name = null, props = noProps, dialect = null
let name = null, props = {}, dialect = null
let decl = this.ast ? this.ast.literals.find(l => l.literal == expr.value) : null
if (decl) ({name, props, dialect} = this.b.nodeInfo(decl.props, "d", expr.value))

Expand Down
20 changes: 9 additions & 11 deletions src/grammar.ts
Expand Up @@ -18,7 +18,10 @@ const enum TermFlag {

export type Props = {[name: string]: string}

export const noProps: Props = Object.create(null)
export function hasProps(props: Props) {
for (let _p in props) return true
return false
}

let termHash = 0

Expand All @@ -31,15 +34,10 @@ export class Term {
constructor(readonly name: string,
private flags: number,
readonly nodeName: string | null,
public props: Props = noProps) {
nope: { // Make sure props == noProps when the object is empty
for (let _ in props) break nope
this.props = noProps
}
}
readonly props: Props = {}) {}

toString() { return this.name }
get nodeType() { return this.top || this.nodeName != null || this.props != noProps || this.repeated }
get nodeType() { return this.top || this.nodeName != null || hasProps(this.props) || this.repeated }
get terminal() { return (this.flags & TermFlag.Terminal) > 0 }
get eof() { return (this.flags & TermFlag.Eof) > 0 }
get error() { return "error" in this.props }
Expand All @@ -66,7 +64,7 @@ export class TermSet {
this.error = this.term("⚠", "⚠", TermFlag.Preserve)
}

term(name: string, nodeName: string | null, flags: number = 0, props: Props = noProps) {
term(name: string, nodeName: string | null, flags: number = 0, props: Props = {}) {
let term = new Term(name, flags, nodeName, props)
this.terms.push(term)
this.names[name] = term
Expand All @@ -79,11 +77,11 @@ export class TermSet {
return term
}

makeTerminal(name: string, nodeName: string | null, props = noProps) {
makeTerminal(name: string, nodeName: string | null, props = {}) {
return this.term(name, nodeName, TermFlag.Terminal, props)
}

makeNonTerminal(name: string, nodeName: string | null, props = noProps) {
makeNonTerminal(name: string, nodeName: string | null, props = {}) {
return this.term(name, nodeName, 0, props)
}

Expand Down

0 comments on commit 61045f7

Please sign in to comment.