Support Setting Arrays/Fields
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -93,6 +93,30 @@ extension TypedIdentifier: EvaluatableExpression {
|
||||
}
|
||||
}
|
||||
|
||||
// Variables are evaluatable because they can be looked up by identifiers.
|
||||
extension TypedIdentifier: EvaluatableLValueExpression {
|
||||
public func set(
|
||||
to: any Common.P4Value, inScopes scopes: Common.ValueScopes, duringExecution execution: ProgramExecution
|
||||
) -> Common.Result<(Common.ValueScopes, P4Value)> {
|
||||
if case .Error(let e) = scopes.lookup(identifier: self) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
return .Ok((scopes.set(identifier: self, withValue: to), to))
|
||||
}
|
||||
|
||||
public func check(to: any Common.EvaluatableExpression, inScopes scopes: Common.TypeScopes) -> Result<()> {
|
||||
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
|
||||
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
|
||||
}
|
||||
|
||||
if !type.eq(rhs: to.type()) {
|
||||
return .Error(Error(withMessage: "Cannot assign value with type \(to.type()) to identifier \(self) with type \(type)"))
|
||||
}
|
||||
return .Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
public func binary_equal_operator_evaluator(left: P4Value, right: P4Value) -> P4Value {
|
||||
if left.eq(rhs: right) {
|
||||
return P4BooleanValue(withValue: true)
|
||||
@@ -141,7 +165,7 @@ extension ArrayAccessExpression: EvaluatableExpression {
|
||||
}
|
||||
let accessed = array.access(indexor_int.access())
|
||||
|
||||
return accessed.evaluate(execution: execution)
|
||||
return .Ok(accessed)
|
||||
}
|
||||
|
||||
public func type() -> any Common.P4Type {
|
||||
@@ -149,6 +173,56 @@ extension ArrayAccessExpression: EvaluatableExpression {
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
public func set(
|
||||
to: any Common.P4Value, inScopes scopes: Common.ValueScopes, duringExecution execution: ProgramExecution
|
||||
) -> Common.Result<(Common.ValueScopes, P4Value)> {
|
||||
// For purposes of documentation, assume the field access expression we are evaluating is
|
||||
// (strct_id)[indexor] = new_value
|
||||
// where strct_id expands to
|
||||
// (identifier.field_id1.field_id2...).field_id = new_field_value
|
||||
|
||||
// First, evaluate strct_id and make sure that it names a struct.
|
||||
let maybe_value = self.name.evaluate(execution: execution)
|
||||
guard case .Ok(let value) = maybe_value else {
|
||||
return Result.Error(Error(withMessage: "\(self.name) cannot be evaluated: \(maybe_value.error()!)"))
|
||||
}
|
||||
guard let array_value = value as? P4ArrayValue else {
|
||||
return Result.Error(Error(withMessage: "\(self.name) does not identify a struct"))
|
||||
}
|
||||
|
||||
// Now, get the indexor!
|
||||
let maybe_indexor_value = self.indexor.evaluate(execution: execution)
|
||||
guard case .Ok(let indexor_value) = maybe_indexor_value else {
|
||||
return Result.Error(Error(withMessage: "\(self.indexor) cannot be evaluated: \(maybe_indexor_value.error()!)"))
|
||||
}
|
||||
guard let indexor_int = indexor_value as? P4IntValue else {
|
||||
return Result.Error(Error(withMessage: "\(self.indexor) cannot be used to index an array"))
|
||||
}
|
||||
|
||||
// Now we have an array and an index!
|
||||
|
||||
// Update field_id of that structure and get the new structure value.
|
||||
let set_result = array_value.set(index: indexor_int.access(), to: to)
|
||||
guard case .Ok(let new_array_value) = set_result else {
|
||||
return .Error(set_result.error()!)
|
||||
}
|
||||
|
||||
let array_lvalue = self.name as! EvaluatableLValueExpression
|
||||
return array_lvalue.set(to: new_array_value, inScopes: scopes, duringExecution: execution)
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.TypeScopes
|
||||
) -> Common.Result<()> {
|
||||
|
||||
if !self.type.value_type().eq(rhs: to.type()) {
|
||||
return .Error(Error(withMessage: "Cannot assign value of type \(to.type()) to array with values of type \(self.name.type())"))
|
||||
}
|
||||
return .Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: Common.ProgramExecution) -> Common.Result<any Common.P4Value> {
|
||||
let maybe_struct = self.strct.evaluate(execution: execution)
|
||||
@@ -172,3 +246,48 @@ extension FieldAccessExpression: EvaluatableExpression {
|
||||
return self.field.type
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: EvaluatableLValueExpression {
|
||||
public func set(
|
||||
to: any Common.P4Value, inScopes scopes: Common.ValueScopes, duringExecution execution: ProgramExecution
|
||||
) -> Common.Result<(Common.ValueScopes, P4Value)> {
|
||||
// For purposes of documentation, assume the field access expression we are evaluating is
|
||||
// (strct_id).field_id = new_field_value
|
||||
// where strct_id expands to
|
||||
// (identifier.field_id1.field_id2...).field_id = new_field_value
|
||||
|
||||
// First, evaluate strct_id and make sure that it names a struct.
|
||||
let maybe_value = self.strct.evaluate(execution: execution)
|
||||
guard case .Ok(let value) = maybe_value else {
|
||||
return Result.Error(Error(withMessage: "\(self.strct) cannot be evaluated: \(maybe_value.error()!)"))
|
||||
}
|
||||
|
||||
guard let struct_value = value as? P4StructValue else {
|
||||
return Result.Error(Error(withMessage: "\(self.strct) does not identify a struct"))
|
||||
}
|
||||
|
||||
// Now we know that struct_id identifies a structure value.
|
||||
|
||||
// Update field_id of that structure and get the new structure value.
|
||||
let set_result = struct_value.set(field: self.field, to: to)
|
||||
guard case .Ok(let new_struct_value) = set_result else {
|
||||
return .Error(set_result.error()!)
|
||||
}
|
||||
|
||||
// That new structure value should be assignable to the lvalue that is strct_id.
|
||||
// We use recursion here -- ultimately finding our way to a TypedIdentifier that
|
||||
// will update the scope. Pretty cool!
|
||||
let struct_lvalue = self.strct as! EvaluatableLValueExpression
|
||||
return struct_lvalue.set(to: new_struct_value, inScopes: scopes, duringExecution: execution)
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.TypeScopes
|
||||
) -> Common.Result<()> {
|
||||
|
||||
if !self.field.type.eq(rhs:to.type()) {
|
||||
return .Error(Error(withMessage: "Cannot assign value of type \(to.type()) to field with type \(self.field.type)"))
|
||||
}
|
||||
return .Ok(())
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,13 @@ extension ParserAssignmentStatement: EvaluatableStatement {
|
||||
guard case Result.Ok(let value) = result else {
|
||||
return execution.setError(error: result.error()!)
|
||||
}
|
||||
let updated_scopes = execution.scopes.set(identifier: self.lvalue, withValue: value)
|
||||
|
||||
execution.scopes = updated_scopes
|
||||
let maybe_updated_scopes = self.lvalue.set(
|
||||
to: value, inScopes: execution.scopes, duringExecution: execution)
|
||||
guard case Result.Ok(let updated_scopes) = maybe_updated_scopes else {
|
||||
return execution.setError(error: maybe_updated_scopes.error()!)
|
||||
}
|
||||
execution.scopes = updated_scopes.0
|
||||
|
||||
return execution
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user