Skip to content

Commit

Permalink
Merge pull request #172 from franklinsch/initializers
Browse files Browse the repository at this point in the history
Support contract initializers
  • Loading branch information
franklinsch authored Apr 28, 2018
2 parents 2d81cc5 + 2615956 commit 6f4abeb
Show file tree
Hide file tree
Showing 40 changed files with 695 additions and 184 deletions.
64 changes: 61 additions & 3 deletions Sources/AST/AST.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,33 @@ public struct ContractDeclaration: SourceEntity {
}
}

/// A member in a contract behavior declaration.
///
/// - functionDeclaration: The declaration of a function.
/// - initializerDeclaration: The declaration of an initializer.
public enum ContractBehaviorMember: Equatable {
case functionDeclaration(FunctionDeclaration)
case initializerDeclaration(InitializerDeclaration)
}

/// A Flint contract behavior declaration, i.e. the functions of a contract for a given caller capability group.
public struct ContractBehaviorDeclaration: SourceEntity {
public var contractIdentifier: Identifier
public var capabilityBinding: Identifier?
public var callerCapabilities: [CallerCapability]
public var functionDeclarations: [FunctionDeclaration]
public var members: [ContractBehaviorMember]
public var closeBracketToken: Token

public var sourceLocation: SourceLocation {
return .spanning(contractIdentifier, to: closeBracketToken)
}

public init(contractIdentifier: Identifier, capabilityBinding: Identifier?, callerCapabilities: [CallerCapability], closeBracketToken: Token, functionDeclarations: [FunctionDeclaration]) {
public init(contractIdentifier: Identifier, capabilityBinding: Identifier?, callerCapabilities: [CallerCapability], closeBracketToken: Token, members: [ContractBehaviorMember]) {
self.contractIdentifier = contractIdentifier
self.capabilityBinding = capabilityBinding
self.callerCapabilities = callerCapabilities
self.functionDeclarations = functionDeclarations
self.closeBracketToken = closeBracketToken
self.members = members
}
}

Expand All @@ -73,6 +82,7 @@ public struct ContractBehaviorDeclaration: SourceEntity {
public enum StructMember: Equatable {
case variableDeclaration(VariableDeclaration)
case functionDeclaration(FunctionDeclaration)
case initializerDeclaration(InitializerDeclaration)
}

/// The declaration of a struct.
Expand Down Expand Up @@ -208,6 +218,54 @@ public struct FunctionDeclaration: SourceEntity {
}
}

public struct InitializerDeclaration: SourceEntity {
public var initToken: Token

/// The attributes associated with the function, such as `@payable`.
public var attributes: [Attribute]

/// The modifiers associted with the function, such as `public`.
public var modifiers: [Token]
public var parameters: [Parameter]
public var closeBracketToken: Token
public var body: [Statement]
public var closeBraceToken: Token

public var sourceLocation: SourceLocation {
return initToken.sourceLocation
}

/// The non-implicit parameters of the initializer.
public var explicitParameters: [Parameter] {
return asFunctionDeclaration.explicitParameters
}

/// A function declaration equivalent of the initializer.
public var asFunctionDeclaration: FunctionDeclaration {
let dummyIdentifier = Identifier(identifierToken: Token(kind: .identifier("init"), sourceLocation: initToken.sourceLocation))
return FunctionDeclaration(funcToken: initToken, attributes: attributes, modifiers: modifiers, identifier: dummyIdentifier, parameters: parameters, closeBracketToken: closeBracketToken, resultType: nil, body: body, closeBraceToken: closeBracketToken)
}

/// The parameters of the initializer, as variable declaration values.
public var parametersAsVariableDeclarations: [VariableDeclaration] {
return asFunctionDeclaration.parametersAsVariableDeclarations
}

public var isPublic: Bool {
return asFunctionDeclaration.isPublic
}

public init(initToken: Token, attributes: [Attribute], modifiers: [Token], parameters: [Parameter], closeBracketToken: Token, body: [Statement], closeBraceToken: Token) {
self.initToken = initToken
self.attributes = attributes
self.modifiers = modifiers
self.parameters = parameters
self.closeBracketToken = closeBracketToken
self.body = body
self.closeBraceToken = closeBracketToken
}
}

/// A function attribute, such as `@payable`.
public struct Attribute: SourceEntity {
var kind: Kind
Expand Down
78 changes: 50 additions & 28 deletions Sources/AST/ASTDumper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ public class ASTDumper {
for callerCapability in contractBehaviorDeclaration.callerCapabilities {
self.dump(callerCapability)
}
for functionDeclaration in contractBehaviorDeclaration.functionDeclarations {
self.dump(functionDeclaration)
for member in contractBehaviorDeclaration.members {
self.dump(member)
}
self.dump(contractBehaviorDeclaration.closeBracketToken)
}
Expand All @@ -95,14 +95,25 @@ public class ASTDumper {
}
}

func dump(_ structMember: StructMember) {
switch structMember {
case .functionDeclaration(let functionDeclaration):
self.dump(functionDeclaration)
case .variableDeclaration(let variableDeclaration):
self.dump(variableDeclaration)
}
func dump(_ structMember: StructMember) {
switch structMember {
case .functionDeclaration(let functionDeclaration):
self.dump(functionDeclaration)
case .variableDeclaration(let variableDeclaration):
self.dump(variableDeclaration)
case .initializerDeclaration(let initializerDeclaration):
self.dump(initializerDeclaration)
}
}

func dump(_ contractBehaviorMember: ContractBehaviorMember) {
switch contractBehaviorMember {
case .functionDeclaration(let functionDeclaration):
self.dump(functionDeclaration)
case .initializerDeclaration(let initializerDeclaration):
self.dump(initializerDeclaration)
}
}

func dump(_ variableDeclaration: VariableDeclaration) {
writeNode("VariableDeclaration") {
Expand All @@ -120,34 +131,45 @@ public class ASTDumper {

func dump(_ functionDeclaration: FunctionDeclaration) {
writeNode("FunctionDeclaration") {
for attribute in functionDeclaration.attributes {
self.dump(attribute)
}
self.dumpNodeContents(functionDeclaration)
}
}

for modifier in functionDeclaration.modifiers {
self.dump(modifier)
}

self.dump(functionDeclaration.funcToken)
func dump(_ initializerDeclaration: InitializerDeclaration) {
writeNode("InitializerDeclaration") {
self.dumpNodeContents(initializerDeclaration.asFunctionDeclaration)
}
}

func dumpNodeContents(_ functionDeclaration: FunctionDeclaration) {
for attribute in functionDeclaration.attributes {
self.dump(attribute)
}

self.dump(functionDeclaration.identifier)
for modifier in functionDeclaration.modifiers {
self.dump(modifier)
}

for parameter in functionDeclaration.parameters {
self.dump(parameter)
}
self.dump(functionDeclaration.funcToken)

self.dump(functionDeclaration.closeBracketToken)
self.dump(functionDeclaration.identifier)

if let resultType = functionDeclaration.resultType {
self.writeNode("ResultType") {
self.dump(resultType)
}
}
for parameter in functionDeclaration.parameters {
self.dump(parameter)
}

for statement in functionDeclaration.body {
self.dump(statement)
self.dump(functionDeclaration.closeBracketToken)

if let resultType = functionDeclaration.resultType {
self.writeNode("ResultType") {
self.dump(resultType)
}
}

for statement in functionDeclaration.body {
self.dump(statement)
}
}

func dump(_ parameter: Parameter) {
Expand Down
24 changes: 22 additions & 2 deletions Sources/AST/ASTPass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ public protocol ASTPass {
func process(structDeclaration: StructDeclaration, passContext: ASTPassContext) -> ASTPassResult<StructDeclaration>
func process(structMember: StructMember, passContext: ASTPassContext) -> ASTPassResult<StructMember>
func process(contractBehaviorDeclaration: ContractBehaviorDeclaration, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorDeclaration>
func process(contractBehaviorMember: ContractBehaviorMember, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorMember>
func process(variableDeclaration: VariableDeclaration, passContext: ASTPassContext) -> ASTPassResult<VariableDeclaration>
func process(functionDeclaration: FunctionDeclaration, passContext: ASTPassContext) -> ASTPassResult<FunctionDeclaration>
func process(initializerDeclaration: InitializerDeclaration, passContext: ASTPassContext) -> ASTPassResult<InitializerDeclaration>
func process(attribute: Attribute, passContext: ASTPassContext) -> ASTPassResult<Attribute>
func process(parameter: Parameter, passContext: ASTPassContext) -> ASTPassResult<Parameter>
func process(typeAnnotation: TypeAnnotation, passContext: ASTPassContext) -> ASTPassResult<TypeAnnotation>
Expand All @@ -38,9 +40,11 @@ public protocol ASTPass {
func postProcess(contractDeclaration: ContractDeclaration, passContext: ASTPassContext) -> ASTPassResult<ContractDeclaration>
func postProcess(structMember: StructMember, passContext: ASTPassContext) -> ASTPassResult<StructMember>
func postProcess(contractBehaviorDeclaration: ContractBehaviorDeclaration, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorDeclaration>
func postProcess(contractBehaviorMember: ContractBehaviorMember, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorMember>
func postProcess(structDeclaration: StructDeclaration, passContext: ASTPassContext) -> ASTPassResult<StructDeclaration>
func postProcess(variableDeclaration: VariableDeclaration, passContext: ASTPassContext) -> ASTPassResult<VariableDeclaration>
func postProcess(functionDeclaration: FunctionDeclaration, passContext: ASTPassContext) -> ASTPassResult<FunctionDeclaration>
func postProcess(initializerDeclaration: InitializerDeclaration, passContext: ASTPassContext) -> ASTPassResult<InitializerDeclaration>
func postProcess(attribute: Attribute, passContext: ASTPassContext) -> ASTPassResult<Attribute>
func postProcess(parameter: Parameter, passContext: ASTPassContext) -> ASTPassResult<Parameter>
func postProcess(typeAnnotation: TypeAnnotation, passContext: ASTPassContext) -> ASTPassResult<TypeAnnotation>
Expand Down Expand Up @@ -88,6 +92,10 @@ public struct AnyASTPass: ASTPass {
return base.process(contractBehaviorDeclaration: contractBehaviorDeclaration, passContext: passContext)
}

public func process(contractBehaviorMember: ContractBehaviorMember, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorMember> {
return base.process(contractBehaviorMember: contractBehaviorMember, passContext: passContext)
}

public func process(variableDeclaration: VariableDeclaration, passContext: ASTPassContext) -> ASTPassResult<VariableDeclaration> {
return base.process(variableDeclaration: variableDeclaration, passContext: passContext)
}
Expand All @@ -96,6 +104,10 @@ public struct AnyASTPass: ASTPass {
return base.process(functionDeclaration: functionDeclaration, passContext: passContext)
}

public func process(initializerDeclaration: InitializerDeclaration, passContext: ASTPassContext) -> ASTPassResult<InitializerDeclaration> {
return base.process(initializerDeclaration: initializerDeclaration, passContext: passContext)
}

public func process(attribute: Attribute, passContext: ASTPassContext) -> ASTPassResult<Attribute> {
return base.process(attribute: attribute, passContext: passContext)
}
Expand Down Expand Up @@ -169,12 +181,16 @@ public struct AnyASTPass: ASTPass {
return base.postProcess(contractBehaviorDeclaration: contractBehaviorDeclaration, passContext: passContext)
}

public func postProcess(contractBehaviorMember: ContractBehaviorMember, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorMember> {
return base.postProcess(contractBehaviorMember: contractBehaviorMember, passContext: passContext)
}

public func postProcess(structDeclaration: StructDeclaration, passContext: ASTPassContext) -> ASTPassResult<StructDeclaration> {
return base.process(structDeclaration: structDeclaration, passContext: passContext)
return base.postProcess(structDeclaration: structDeclaration, passContext: passContext)
}

public func postProcess(structMember: StructMember, passContext: ASTPassContext) -> ASTPassResult<StructMember> {
return base.process(structMember: structMember, passContext: passContext)
return base.postProcess(structMember: structMember, passContext: passContext)
}

public func postProcess(variableDeclaration: VariableDeclaration, passContext: ASTPassContext) -> ASTPassResult<VariableDeclaration> {
Expand All @@ -185,6 +201,10 @@ public struct AnyASTPass: ASTPass {
return base.postProcess(functionDeclaration: functionDeclaration, passContext: passContext)
}

public func postProcess(initializerDeclaration: InitializerDeclaration, passContext: ASTPassContext) -> ASTPassResult<InitializerDeclaration> {
return base.postProcess(initializerDeclaration: initializerDeclaration, passContext: passContext)
}

public func postProcess(attribute: Attribute, passContext: ASTPassContext) -> ASTPassResult<Attribute> {
return base.postProcess(attribute: attribute, passContext: passContext)
}
Expand Down
45 changes: 43 additions & 2 deletions Sources/AST/ASTVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ public struct ASTVisitor<Pass: ASTPass> {

let typeScopeContext = processResult.passContext.scopeContext

processResult.element.functionDeclarations = processResult.element.functionDeclarations.map { functionDeclaration in
processResult.element.members = processResult.element.members.map { member in
processResult.passContext.scopeContext = typeScopeContext
return processResult.combining(visit(functionDeclaration, passContext: processResult.passContext))
return processResult.combining(visit(member, passContext: processResult.passContext))
}

processResult.passContext.contractBehaviorDeclarationContext = nil
Expand Down Expand Up @@ -137,12 +137,28 @@ public struct ASTVisitor<Pass: ASTPass> {
processResult.element = .functionDeclaration(processResult.combining(visit(functionDeclaration, passContext: processResult.passContext)))
case .variableDeclaration(let variableDeclaration):
processResult.element = .variableDeclaration(processResult.combining(visit(variableDeclaration, passContext: processResult.passContext)))
case .initializerDeclaration(let initializerDeclaration):
processResult.element = .initializerDeclaration(processResult.combining(visit(initializerDeclaration, passContext: processResult.passContext)))
}

let postProcessResult = pass.postProcess(structMember: processResult.element, passContext: processResult.passContext)
return ASTPassResult(element: postProcessResult.element, diagnostics: processResult.diagnostics + postProcessResult.diagnostics, passContext: postProcessResult.passContext)
}

func visit(_ contractBehaviorMember: ContractBehaviorMember, passContext: ASTPassContext) -> ASTPassResult<ContractBehaviorMember> {
var processResult = pass.process(contractBehaviorMember: contractBehaviorMember, passContext: passContext)

switch processResult.element {
case .functionDeclaration(let functionDeclaration):
processResult.element = .functionDeclaration(processResult.combining(visit(functionDeclaration, passContext: processResult.passContext)))
case .initializerDeclaration(let initializerDeclaration):
processResult.element = .initializerDeclaration(processResult.combining(visit(initializerDeclaration, passContext: processResult.passContext)))
}

let postProcessResult = pass.postProcess(contractBehaviorMember: processResult.element, passContext: processResult.passContext)
return ASTPassResult(element: postProcessResult.element, diagnostics: processResult.diagnostics + postProcessResult.diagnostics, passContext: postProcessResult.passContext)
}

func visit(_ variableDeclaration: VariableDeclaration, passContext: ASTPassContext) -> ASTPassResult<VariableDeclaration> {
var processResult = pass.process(variableDeclaration: variableDeclaration, passContext: passContext)

Expand Down Expand Up @@ -186,6 +202,31 @@ public struct ASTVisitor<Pass: ASTPass> {
return ASTPassResult(element: postProcessResult.element, diagnostics: processResult.diagnostics + postProcessResult.diagnostics, passContext: postProcessResult.passContext)
}

func visit(_ initializerDeclaration: InitializerDeclaration, passContext: ASTPassContext) -> ASTPassResult<InitializerDeclaration> {
var processResult = pass.process(initializerDeclaration: initializerDeclaration, passContext: passContext)

processResult.element.attributes = processResult.element.attributes.map { attribute in
return processResult.combining(visit(attribute, passContext: processResult.passContext))
}

processResult.element.parameters = processResult.element.parameters.map { parameter in
return processResult.combining(visit(parameter, passContext: processResult.passContext))
}

let functionDeclaration = initializerDeclaration.asFunctionDeclaration

processResult.passContext.scopeContext!.localVariables.append(contentsOf: functionDeclaration.parametersAsVariableDeclarations)

processResult.element.body = processResult.element.body.map { statement in
return processResult.combining(visit(statement, passContext: processResult.passContext))
}

processResult.passContext.functionDeclarationContext = nil

let postProcessResult = pass.postProcess(initializerDeclaration: processResult.element, passContext: processResult.passContext)
return ASTPassResult(element: postProcessResult.element, diagnostics: processResult.diagnostics + postProcessResult.diagnostics, passContext: postProcessResult.passContext)
}

func visit(_ attribute: Attribute, passContext: ASTPassContext) -> ASTPassResult<Attribute> {
let processResult = pass.process(attribute: attribute, passContext: passContext)

Expand Down
2 changes: 1 addition & 1 deletion Sources/AST/ASTVisitorContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public struct StructDeclarationContext {
}
}

/// Contextual information used when visiting statements in a function, such as if it is mutating or note.
/// Contextual information used when visiting statements in a function, such as if it is mutating or not.
public struct FunctionDeclarationContext {
public var declaration: FunctionDeclaration

Expand Down
11 changes: 11 additions & 0 deletions Sources/AST/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ public struct Environment {
return .failure(candidates: candidates)
}

/// Set the public initializer for the given contract. A contract should have at most one public initializer.
public mutating func setPublicInitializer(_ publicInitializer: InitializerDeclaration, forContract contract: RawTypeIdentifier) {
types[contract]!.publicInitializer = publicInitializer
}

/// The public initializer for the given contract. A contract should have at most one public initializer.
public func publicInitializer(forContract contract: RawTypeIdentifier) -> InitializerDeclaration? {
return types[contract]!.publicInitializer
}

/// Whether two caller capability groups are compatible, i.e. whether a function with caller capabilities `source` is
/// able to call a function which require caller capabilities `target`.
func areCallerCapabilitiesCompatible(source: [CallerCapability], target: [CallerCapability]) -> Bool {
Expand Down Expand Up @@ -309,6 +319,7 @@ public struct TypeInformation {
var orderedProperties = [String]()
var properties = [String: PropertyInformation]()
var functions = [String: [FunctionInformation]]()
var publicInitializer: InitializerDeclaration? = nil
}

/// Information about a property defined in a type, such as its type and generic arguments.
Expand Down
Loading

0 comments on commit 6f4abeb

Please sign in to comment.