Streamlined looping
This commit is contained in:
@@ -65,6 +65,15 @@ enum TokenType {
|
|||||||
case MULTIPLICATION
|
case MULTIPLICATION
|
||||||
case DIVISION
|
case DIVISION
|
||||||
|
|
||||||
|
case LOGICAL_AND
|
||||||
|
case LOGICAL_OR
|
||||||
|
case EQUAL
|
||||||
|
case NOT_EQUAL
|
||||||
|
case LESS_THAN
|
||||||
|
case LESS_THAN_OR_EQUAL_TO
|
||||||
|
case GREATER_THAN
|
||||||
|
case GREATER_THAN_OR_EQUAL_TO
|
||||||
|
|
||||||
case UNDEFINED
|
case UNDEFINED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +85,7 @@ struct Token {
|
|||||||
typealias Construct = [Element]
|
typealias Construct = [Element]
|
||||||
|
|
||||||
enum Element {
|
enum Element {
|
||||||
|
case Loop(type: ConstructType)
|
||||||
case Construct(type: ConstructType)
|
case Construct(type: ConstructType)
|
||||||
case Token(type: TokenType)
|
case Token(type: TokenType)
|
||||||
}
|
}
|
||||||
@@ -86,6 +96,14 @@ enum ConstructVariant {
|
|||||||
case Multiplication
|
case Multiplication
|
||||||
case Division
|
case Division
|
||||||
|
|
||||||
|
case LessThan
|
||||||
|
case LessThanOrEqualTo
|
||||||
|
case GreaterThan
|
||||||
|
case GreaterThanOrEqualTo
|
||||||
|
|
||||||
|
case EqualTo
|
||||||
|
case NotEqualTo
|
||||||
|
|
||||||
// Unary operation variants
|
// Unary operation variants
|
||||||
case Negation
|
case Negation
|
||||||
case BitwiseCompliment
|
case BitwiseCompliment
|
||||||
@@ -118,14 +136,22 @@ enum ConstructVariant {
|
|||||||
|
|
||||||
enum ConstructType {
|
enum ConstructType {
|
||||||
case UnaryOperator
|
case UnaryOperator
|
||||||
|
|
||||||
case MultiplicationPriorityOperator
|
case MultiplicationPriorityOperator
|
||||||
case AdditionPriorityOperator
|
case AdditionPriorityOperator
|
||||||
case Expression
|
case InequalityPriorityOperator
|
||||||
case Factor
|
case EqualityPriorityOperator
|
||||||
case Term
|
|
||||||
case Statement
|
|
||||||
case Function
|
|
||||||
case Program
|
case Program
|
||||||
|
case Function
|
||||||
|
case Statement
|
||||||
|
case Expression
|
||||||
|
case LogicalAndExpression
|
||||||
|
case EqualityExpression
|
||||||
|
case RelationalExpression
|
||||||
|
case AdditiveExpression
|
||||||
|
case Term
|
||||||
|
case Factor
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConstructDefinitions {
|
struct ConstructDefinitions {
|
||||||
@@ -164,17 +190,41 @@ let constructDefinitions: Dictionary<ConstructType, Dictionary<ConstructVariant,
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
.InequalityPriorityOperator: [
|
||||||
|
.LessThan: [
|
||||||
|
.Token(type: .LESS_THAN),
|
||||||
|
],
|
||||||
|
.LessThanOrEqualTo: [
|
||||||
|
.Token(type: .LESS_THAN_OR_EQUAL_TO),
|
||||||
|
],
|
||||||
|
.GreaterThan: [
|
||||||
|
.Token(type: .GREATER_THAN),
|
||||||
|
],
|
||||||
|
.GreaterThanOrEqualTo: [
|
||||||
|
.Token(type: .GREATER_THAN_OR_EQUAL_TO),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
.EqualityPriorityOperator: [
|
||||||
|
.EqualTo: [
|
||||||
|
.Token(type: .EQUAL),
|
||||||
|
],
|
||||||
|
.NotEqualTo: [
|
||||||
|
.Token(type: .NOT_EQUAL),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
.Expression: [
|
.Expression: [
|
||||||
.TermSequence: [
|
.TermSequence: [
|
||||||
.Construct(type: .Term),
|
.Construct(type: .Term),
|
||||||
.Construct(type: .AdditionPriorityOperator),
|
.Loop(type: .AdditionPriorityOperator),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
.Term: [
|
.Term: [
|
||||||
.FactorSequence: [
|
.FactorSequence: [
|
||||||
.Construct(type: .Factor),
|
.Construct(type: .Factor),
|
||||||
.Construct(type: .MultiplicationPriorityOperator),
|
.Loop(type: .MultiplicationPriorityOperator),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -336,6 +386,14 @@ func lex(string: String) -> [Substring] {
|
|||||||
line = line.replacing("+", with: " + ")
|
line = line.replacing("+", with: " + ")
|
||||||
line = line.replacing("*", with: " * ")
|
line = line.replacing("*", with: " * ")
|
||||||
line = line.replacing("/", with: " / ")
|
line = line.replacing("/", with: " / ")
|
||||||
|
line = line.replacing("&&", with: " && ")
|
||||||
|
line = line.replacing("||", with: " || ")
|
||||||
|
line = line.replacing("==", with: " == ")
|
||||||
|
line = line.replacing("!=", with: " != ")
|
||||||
|
line = line.replacing("<", with: " < ")
|
||||||
|
line = line.replacing("<=", with: " <= ")
|
||||||
|
line = line.replacing(">", with: " > ")
|
||||||
|
line = line.replacing(">=", with: " >= ")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let tokens: [Substring] = line.split(separator: try Regex(" +"))
|
let tokens: [Substring] = line.split(separator: try Regex(" +"))
|
||||||
@@ -519,7 +577,7 @@ func parse(lexed: [Substring]) -> String {
|
|||||||
|
|
||||||
let abstractSyntaxTree = SyntaxTreeNode(.Root)
|
let abstractSyntaxTree = SyntaxTreeNode(.Root)
|
||||||
|
|
||||||
if validateConstruct(program.variants[.SingleFunction]!, tokens: &tokens, node: abstractSyntaxTree, loopingEnabled: false) != .Invalid {
|
if validateConstruct(type: .Program, variant: .SingleFunction, tokens: &tokens, node: abstractSyntaxTree) != .Invalid {
|
||||||
print("Success")
|
print("Success")
|
||||||
print(abstractSyntaxTree.text())
|
print(abstractSyntaxTree.text())
|
||||||
print("Assembly:")
|
print("Assembly:")
|
||||||
@@ -539,7 +597,7 @@ enum Validity {
|
|||||||
case Break
|
case Break
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateConstruct(_ construct: Construct, tokens: inout [Token], node: SyntaxTreeNode, loopingEnabled: Bool) -> Validity {
|
func validateConstruct(type: ConstructType, variant: ConstructVariant, tokens: inout [Token], node: SyntaxTreeNode) -> Validity {
|
||||||
var indent: String {
|
var indent: String {
|
||||||
var count: Int = 0
|
var count: Int = 0
|
||||||
var child: SyntaxTreeNode = node
|
var child: SyntaxTreeNode = node
|
||||||
@@ -550,10 +608,119 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
|||||||
return String(repeating: " ", count: count)
|
return String(repeating: " ", count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
var loop: Bool = loopingEnabled
|
var loop: Bool = false
|
||||||
repeat {
|
repeat {
|
||||||
|
let construct = constructDefinitions[type]![variant]!
|
||||||
for element in construct {
|
for element in construct {
|
||||||
switch element {
|
switch element {
|
||||||
|
case .Loop(let constructType):
|
||||||
|
/*
|
||||||
|
var matchingOperator: Bool = false
|
||||||
|
|
||||||
|
print("\(indent)Determining need for loop")
|
||||||
|
let tokenBackup: [Token] = tokens
|
||||||
|
for constructVariant in constructDefinitions[constructType]!.keys {
|
||||||
|
let childNode = node.addChild(value: variant)
|
||||||
|
print("\(indent)Testing operator \(constructType)::\(constructVariant)")
|
||||||
|
let valid = validateConstruct(type: constructType, variant: constructVariant, tokens: &tokens, node: node)
|
||||||
|
if valid == .Panic {
|
||||||
|
return .Invalid
|
||||||
|
} else if valid == .Invalid {
|
||||||
|
tokens = tokenBackup
|
||||||
|
_ = node.popLastChild()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matchingOperator = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
loop = matchingOperator
|
||||||
|
if loop {
|
||||||
|
print("\(indent)Looping")
|
||||||
|
} else {
|
||||||
|
print("\(indent)Not looping")
|
||||||
|
return .Valid
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var valid: Validity = .Invalid
|
||||||
|
var matchingOperator: Bool = false
|
||||||
|
print("\(indent)Determining need to loop construct of type \(constructType)")
|
||||||
|
let tokenBackup: [Token] = tokens
|
||||||
|
for constructVariant in constructDefinitions[constructType]!.keys {
|
||||||
|
let childNode = node.addChild(value: constructVariant)
|
||||||
|
print("\(indent)Testing operator \(constructType)::\(constructVariant)")
|
||||||
|
|
||||||
|
valid = validateConstruct(type: constructType, variant: constructVariant, tokens: &tokens, node: childNode)
|
||||||
|
if valid == .Panic {
|
||||||
|
print("\(indent)Fail: panic (variant \"\(constructVariant)\"))\n")
|
||||||
|
return .Invalid
|
||||||
|
} else if valid == .Invalid {
|
||||||
|
tokens = tokenBackup
|
||||||
|
_ = node.popLastChild()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matchingOperator = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
loop = matchingOperator
|
||||||
|
|
||||||
|
if loop {
|
||||||
|
print("\(indent)Looping")
|
||||||
|
} else {
|
||||||
|
print("\(indent)Not looping")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if valid == .Invalid {
|
||||||
|
print("\(indent)Subconstruct validation failed")
|
||||||
|
return .Invalid
|
||||||
|
} else if valid == .Break {
|
||||||
|
print("\(indent)End validate subconstruct (variant \"\(validVariant) by breaking\")")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//print("\(indent)End validate subconstruct (variant \"\(validVariant)\")")
|
||||||
|
break
|
||||||
|
|
||||||
|
case .Token(let type):
|
||||||
|
if let token: Token = tokens.popLast() {
|
||||||
|
if type != token.type {
|
||||||
|
print("\(indent)VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
|
||||||
|
return .Invalid
|
||||||
|
}
|
||||||
|
print("\(indent)Validated token \"\(token.content)\"")
|
||||||
|
|
||||||
|
if token.type == .LITERAL_INTEGER {
|
||||||
|
node.value = String(token.content)
|
||||||
|
}
|
||||||
|
else if token.type == .IDENTIFIER {
|
||||||
|
node.value = String(token.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print("\(indent)RAN OUT OF TOKENS")
|
||||||
|
return .Invalid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
case .Construct(let type):
|
case .Construct(let type):
|
||||||
print("\(indent)Begin validate subconstruct (type \"\(type)\")")
|
print("\(indent)Begin validate subconstruct (type \"\(type)\")")
|
||||||
|
|
||||||
@@ -568,7 +735,7 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
|||||||
}
|
}
|
||||||
|
|
||||||
print("\(indent)Testing variant \(variant) (Loop = \(loop)) (Loopable = \(loopable))")
|
print("\(indent)Testing variant \(variant) (Loop = \(loop)) (Loopable = \(loopable))")
|
||||||
valid = validateConstruct(constructDefinitions[type]![variant]!, tokens: &tokens, node: childNode, loopingEnabled: loopable)
|
valid = validateConstruct(type: type, variant: variant, tokens: &tokens, node: childNode)
|
||||||
if valid == .Panic {
|
if valid == .Panic {
|
||||||
print("\(indent)Fail: panic (variant \"\(variant)\"))\n")
|
print("\(indent)Fail: panic (variant \"\(variant)\"))\n")
|
||||||
return .Invalid
|
return .Invalid
|
||||||
@@ -587,38 +754,6 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if loopingEnabled {
|
|
||||||
// Factor looping nonsense
|
|
||||||
if type == .Factor {
|
|
||||||
let nextToken: Token = tokens[tokens.count - 1]
|
|
||||||
if nextToken.type == .MULTIPLICATION || nextToken.type == .DIVISION {
|
|
||||||
print("\(indent)Looping due to factor")
|
|
||||||
loop = true
|
|
||||||
} else {
|
|
||||||
if node.children.count != 0 {
|
|
||||||
print("\(indent)Breaking out of factor loop")
|
|
||||||
loop = false
|
|
||||||
return .Break
|
|
||||||
} else {
|
|
||||||
print("\(indent)ERROR: FactorSequence has no children")
|
|
||||||
return .Panic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Term looping nonsense
|
|
||||||
else if type == .Term {
|
|
||||||
let nextToken: Token = tokens[tokens.count - 1]
|
|
||||||
if nextToken.type == .ADDITION || nextToken.type == .NEGATION {
|
|
||||||
print("\(indent)Looping due to term")
|
|
||||||
loop = true
|
|
||||||
} else {
|
|
||||||
print("\(indent)Breaking out of term loop")
|
|
||||||
loop = false
|
|
||||||
return .Break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -678,6 +813,14 @@ func categorizeToken(token: Substring) -> TokenType {
|
|||||||
else if token.firstMatch(of: /^\+$/) != nil { return .ADDITION }
|
else if token.firstMatch(of: /^\+$/) != nil { return .ADDITION }
|
||||||
else if token.firstMatch(of: /^\*$/) != nil { return .MULTIPLICATION }
|
else if token.firstMatch(of: /^\*$/) != nil { return .MULTIPLICATION }
|
||||||
else if token.firstMatch(of: /^\/$/) != nil { return .DIVISION }
|
else if token.firstMatch(of: /^\/$/) != nil { return .DIVISION }
|
||||||
|
else if token.firstMatch(of: /^&&$/) != nil { return .LOGICAL_AND }
|
||||||
|
else if token.firstMatch(of: /^||$/) != nil { return .LOGICAL_OR }
|
||||||
|
else if token.firstMatch(of: /^==$/) != nil { return .EQUAL }
|
||||||
|
else if token.firstMatch(of: /^!=$/) != nil { return .NOT_EQUAL }
|
||||||
|
else if token.firstMatch(of: /^<$/) != nil { return .LESS_THAN }
|
||||||
|
else if token.firstMatch(of: /^<=$/) != nil { return .LESS_THAN_OR_EQUAL_TO }
|
||||||
|
else if token.firstMatch(of: /^>$/) != nil { return .GREATER_THAN }
|
||||||
|
else if token.firstMatch(of: /^>=$/) != nil { return .GREATER_THAN_OR_EQUAL_TO }
|
||||||
|
|
||||||
return .UNDEFINED
|
return .UNDEFINED
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user