Streamlined looping

This commit is contained in:
2026-01-31 23:31:45 -05:00
parent cb13f09ae5
commit 757cf37578

View File

@@ -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
} }