Initial Array Access Implementation
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -17,10 +17,17 @@
|
||||
|
||||
open class ProgramExecution: CustomStringConvertible {
|
||||
public var scopes: ValueScopes = ValueScopes()
|
||||
let initialValues: ValueScopes?
|
||||
var error: Error?
|
||||
var debug: DebugLevel = DebugLevel.Error
|
||||
|
||||
public init() {}
|
||||
public init() {
|
||||
initialValues = .none
|
||||
}
|
||||
|
||||
public init(withGlobalValues values: ValueScopes) {
|
||||
initialValues = values
|
||||
}
|
||||
|
||||
open var description: String {
|
||||
return "Runtime:\nScopes: \(scopes)"
|
||||
@@ -80,6 +87,10 @@ open class ProgramExecution: CustomStringConvertible {
|
||||
new_pe.scopes = new_scopes
|
||||
return new_pe
|
||||
}
|
||||
|
||||
public func initial_values() -> ValueScopes? {
|
||||
return self.initialValues
|
||||
}
|
||||
}
|
||||
|
||||
public typealias ValueScope = Scope<P4Value>
|
||||
|
||||
@@ -198,8 +198,12 @@ public class P4IntValue: P4Value {
|
||||
public init(withValue value: Int) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
public func access() -> Int {
|
||||
return self.value
|
||||
}
|
||||
|
||||
public func eq(rhs: P4Value) -> Bool {
|
||||
print("Int value equal.")
|
||||
guard let int_rhs = rhs as? P4IntValue else {
|
||||
return false
|
||||
}
|
||||
@@ -251,3 +255,49 @@ public class P4StringValue: P4Value {
|
||||
public class Packet {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
/// A P4 array type
|
||||
public struct P4Array: P4Type {
|
||||
|
||||
public static func create() -> any P4Type {
|
||||
return P4Array()
|
||||
}
|
||||
public var description: String {
|
||||
return "Array"
|
||||
}
|
||||
public func eq(rhs: any P4Type) -> Bool {
|
||||
return switch rhs {
|
||||
case is P4Array: true
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An instance of a P4 array
|
||||
public class P4ArrayValue: P4Value {
|
||||
public func type() -> any P4Type {
|
||||
return P4Array()
|
||||
}
|
||||
|
||||
let value: Array<EvaluatableExpression>
|
||||
|
||||
public init(withValue value: Array<EvaluatableExpression>) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
public func access(_ index: Int) -> EvaluatableExpression {
|
||||
return self.value[index]
|
||||
}
|
||||
|
||||
public func eq(rhs: P4Value) -> Bool {
|
||||
guard let _ = rhs as? P4ArrayValue else {
|
||||
return false
|
||||
}
|
||||
// TODO!!
|
||||
return true
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
"\(self.value) of \(self.type()) type"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
public struct Scope<T>: CustomStringConvertible, Sequence {
|
||||
public typealias Element = T
|
||||
public typealias Iterator = Dictionary<Identifier, T>.Values.Iterator
|
||||
public typealias Element = (key: Identifier, value: T)
|
||||
public typealias Iterator = Dictionary<Identifier, T>.Iterator
|
||||
public func makeIterator() -> Iterator {
|
||||
self.symbols.values.makeIterator()
|
||||
self.symbols.makeIterator()
|
||||
}
|
||||
|
||||
var symbols: [Identifier: T] = Dictionary()
|
||||
@@ -123,8 +123,8 @@ public struct Scopes<T>: CustomStringConvertible, Sequence {
|
||||
return .Error(Error(withMessage: "Cannot find \(identifier) in lexical scope."))
|
||||
}
|
||||
|
||||
public typealias Element = T
|
||||
public typealias Iterator = Dictionary<Identifier, T>.Values.Iterator
|
||||
public typealias Element = (key: Identifier, value: T)
|
||||
public typealias Iterator = Dictionary<Identifier, T>.Iterator
|
||||
public func makeIterator() -> Iterator {
|
||||
scopes.last?.makeIterator() ?? Scope<T>().makeIterator()
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ struct Expression {
|
||||
|
||||
let localElementsParsers: [CompilableExpression.Type] = [
|
||||
P4BooleanValue.self, P4StringValue.self, P4IntValue.self, TypedIdentifier.self,
|
||||
BinaryOperatorExpression.self,
|
||||
BinaryOperatorExpression.self, ArrayAccessExpression.self
|
||||
]
|
||||
|
||||
for le_parser in localElementsParsers {
|
||||
@@ -311,3 +311,67 @@ extension BinaryOperatorExpression: CompilableExpression {
|
||||
withLhs: left_hand_side, withRhs: right_hand_side))
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: CompilableExpression {
|
||||
static func compile(node: SwiftTreeSitter.Node, withContext context: CompilerContext) -> Common.Result<(any Common.EvaluatableExpression)?> {
|
||||
let expression = node.child(at: 0)!
|
||||
|
||||
#SkipUnlessNodeType<Node, EvaluatableExpression?>(
|
||||
node: expression, type: "arrayAccessExpression")
|
||||
|
||||
let array_access_expression_node = expression
|
||||
|
||||
var currentChildIdx = 0
|
||||
var currentChildIdxSafe = 1
|
||||
var currentChild: Node? = .none
|
||||
|
||||
// What is the "name" of the array?
|
||||
if array_access_expression_node.childCount < currentChildIdxSafe {
|
||||
return Result.Error(
|
||||
ErrorOnNode(node: node, withError: "Malformed array access expression"))
|
||||
}
|
||||
currentChild = expression.child(at: currentChildIdx)
|
||||
|
||||
#RequireNodeType<Node, EvaluatableExpression?>(
|
||||
node: currentChild!, type: "expression",
|
||||
nice_type_name: "array identifier expression")
|
||||
let array_access_identifier_node = currentChild!
|
||||
|
||||
// Check for the [
|
||||
currentChildIdx = currentChildIdx + 1
|
||||
currentChildIdxSafe = currentChildIdxSafe + 1
|
||||
if array_access_expression_node.childCount < currentChildIdxSafe {
|
||||
return Result.Error(
|
||||
ErrorOnNode(node: node, withError: "Missing [ for array access expression")
|
||||
)
|
||||
}
|
||||
|
||||
// What is the indexor of the array?
|
||||
currentChildIdx = currentChildIdx + 1
|
||||
currentChildIdxSafe = currentChildIdxSafe + 1
|
||||
if array_access_expression_node.childCount < currentChildIdxSafe {
|
||||
return Result.Error(
|
||||
ErrorOnNode(node: node, withError: "Missing indexor expression for array access expression")
|
||||
)
|
||||
}
|
||||
currentChild = array_access_expression_node.child(at: currentChildIdx)
|
||||
|
||||
#RequireNodeType<Node, EvaluatableExpression?>(
|
||||
node: currentChild!, type: "expression",
|
||||
nice_type_name: "array indexor expression")
|
||||
|
||||
let array_access_indexor_node = currentChild!
|
||||
|
||||
let maybe_array_identifier = Expression.Compile(node: array_access_identifier_node, withContext: context)
|
||||
guard case Result.Ok(let array_identifier) = maybe_array_identifier else {
|
||||
return Result.Error(maybe_array_identifier.error()!)
|
||||
}
|
||||
|
||||
let maybe_array_indexor = Expression.Compile(node: array_access_indexor_node, withContext: context)
|
||||
guard case Result.Ok(let array_indexor) = maybe_array_indexor else {
|
||||
return Result.Error(maybe_array_indexor.error()!)
|
||||
}
|
||||
|
||||
return .Ok(ArrayAccessExpression(withName: array_identifier, withIndexor: array_indexor))
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,10 @@ import TreeSitterP4
|
||||
|
||||
public struct Program {
|
||||
public static func Compile(_ source: String) -> Result<P4Lang.Program> {
|
||||
return Program.Compile(source, withGlobalTypes: .none)
|
||||
}
|
||||
|
||||
public static func Compile(_ source: String, withGlobalTypes globalTypes: LexicalScopes?) -> Result<P4Lang.Program> {
|
||||
|
||||
let maybe_parser = ConfigureP4Parser()
|
||||
guard case .Ok(let p) = maybe_parser else {
|
||||
@@ -45,6 +49,11 @@ public struct Program {
|
||||
|
||||
var errors: [Error] = Array()
|
||||
|
||||
// If the caller gave any global types, add them here.
|
||||
if let globalTypes = globalTypes {
|
||||
compilation_context = compilation_context.update(newNames: globalTypes)
|
||||
}
|
||||
|
||||
result?.rootNode?.enumerateNamedChildren { declaration_node in
|
||||
if declaration_node.nodeType != "declaration" {
|
||||
return
|
||||
@@ -185,7 +194,9 @@ public struct Program {
|
||||
}
|
||||
|
||||
// Any of the types that are in the top-level scope should go into the program!
|
||||
program.types = Array(compilation_context.names)
|
||||
program.types = Array(compilation_context.names.map() { (_, v) in
|
||||
v
|
||||
})
|
||||
return Result.Ok(program)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,3 +72,13 @@ public struct BinaryOperatorExpression {
|
||||
self.right = rhs
|
||||
}
|
||||
}
|
||||
|
||||
public struct ArrayAccessExpression {
|
||||
public let indexor: EvaluatableExpression
|
||||
public let name: EvaluatableExpression
|
||||
|
||||
public init(withName name: EvaluatableExpression, withIndexor indexor: EvaluatableExpression) {
|
||||
self.name = name
|
||||
self.indexor = indexor
|
||||
}
|
||||
}
|
||||
@@ -113,3 +113,32 @@ extension BinaryOperatorExpression: EvaluatableExpression {
|
||||
return self.evaluator.1
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: Common.ProgramExecution) -> Common.Result<any Common.P4Value> {
|
||||
let maybe_name = self.name.evaluate(execution: execution)
|
||||
guard case Result.Ok(let name) = maybe_name else {
|
||||
return maybe_name
|
||||
}
|
||||
|
||||
let maybe_indexor = self.indexor.evaluate(execution: execution)
|
||||
guard case Result.Ok(let indexor) = maybe_indexor else {
|
||||
return maybe_indexor
|
||||
}
|
||||
|
||||
guard let indexor_int = indexor as? P4IntValue else {
|
||||
return Result.Error(Error(withMessage: "\(indexor) cannot index an array"))
|
||||
}
|
||||
|
||||
guard let array = name as? P4ArrayValue else {
|
||||
return Result.Error(Error(withMessage: "\(name) does not name an array"))
|
||||
}
|
||||
let accessed = array.access(indexor_int.access())
|
||||
|
||||
return accessed.evaluate(execution: execution)
|
||||
}
|
||||
|
||||
public func type() -> any Common.P4Type {
|
||||
return P4Int.create()
|
||||
}
|
||||
}
|
||||
@@ -120,6 +120,13 @@ extension Parser: ParserExecution {
|
||||
execution = execution.declare(identifier: accept.state().state, withValue: accept)
|
||||
execution = execution.declare(identifier: reject.state().state, withValue: reject)
|
||||
|
||||
// Add initial values to the global scope
|
||||
if let initial = execution.initial_values() {
|
||||
for (name, value) in initial {
|
||||
execution = execution.declare(identifier: name, withValue: value)
|
||||
}
|
||||
}
|
||||
|
||||
// First, add every state to the scope!
|
||||
for state in self.states.states {
|
||||
execution = execution.declare(identifier: state.state, withValue: state)
|
||||
|
||||
@@ -22,16 +22,27 @@ import P4Lang
|
||||
public struct ParserRuntime: CustomStringConvertible {
|
||||
public var parser: Parser
|
||||
|
||||
let initialValues: ValueScopes?
|
||||
|
||||
init(parser: Parser) {
|
||||
self.parser = parser
|
||||
self.initialValues = .none
|
||||
}
|
||||
|
||||
init(parser: Parser, withInitialValues initial: ValueScopes?) {
|
||||
self.parser = parser
|
||||
self.initialValues = initial
|
||||
}
|
||||
|
||||
/// Create a parser runtime from a P4 program
|
||||
public static func create(program: P4Lang.Program) -> Result<ParserRuntime> {
|
||||
return ParserRuntime.create(program: program, withInitialValues: .none)
|
||||
}
|
||||
|
||||
public static func create(program: P4Lang.Program, withInitialValues initial: ValueScopes?) -> Result<ParserRuntime> {
|
||||
return switch program.starting_parser() {
|
||||
case .Ok(let parser):
|
||||
.Ok(P4Runtime.ParserRuntime(parser: parser))
|
||||
.Ok(P4Runtime.ParserRuntime(parser: parser, withInitialValues: initial))
|
||||
case .Error(let error): .Error(error)
|
||||
}
|
||||
}
|
||||
@@ -39,7 +50,13 @@ public struct ParserRuntime: CustomStringConvertible {
|
||||
/// Run the P4 parser on a given packet
|
||||
public func run() -> Result<(ParserState, ProgramExecution)> {
|
||||
|
||||
let (end_state, execution) = parser.execute(execution: ProgramExecution())
|
||||
let pe = if let initial = initialValues {
|
||||
ProgramExecution(withGlobalValues: initial)
|
||||
} else {
|
||||
ProgramExecution()
|
||||
}
|
||||
|
||||
let (end_state, execution) = parser.execute(execution: pe)
|
||||
if let error = execution.getError() {
|
||||
return .Error(error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user