<commit_before>import io/File, text/EscapeSequence
import structs/[HashMap, ArrayList, List, OrderedMultiMap]
import ../frontend/[Token, SourceReader, BuildParams, PathList, AstBuilder]
import ../utils/FileUtils
import Node, FunctionDecl, Visitor, Import, Include, Use, TypeDecl,
       FunctionCall, Type, Declaration, VariableAccess, OperatorDecl,
       Scope, NamespaceDecl, BaseType, FuncType
import tinker/[Response, Resolver, Trail]

Module: class extends Node {

    timesImported := 0
    timesLooped := 0

    path, fullName, simpleName, packageName, underName, pathElement : String
    main := false

    types      := OrderedMultiMap<String, TypeDecl> new()
    functions  := OrderedMultiMap<String, FunctionDecl> new()
    operators  := ArrayList<OperatorDecl> new()

    includes   := ArrayList<Include> new()
    imports    := ArrayList<Import> new()
    namespaces := HashMap<String, NamespaceDecl> new()
    uses       := ArrayList<Use> new()

    funcTypesMap := HashMap<String, FuncType> new()

    body       := Scope new()

    lastModified : Long

    params: BuildParams
    
    init: func ~module (.fullName, =pathElement, =params, .token) {
        super(token)
        this path = fullName clone() replace('/', File separator)
        this fullName = fullName replace(File separator, '/')
        idx := this fullName lastIndexOf('/')

        match idx {
            case -1 =>
                simpleName = this fullName clone()
                packageName = ""
            case =>
                simpleName = this fullName substring(idx + 1)
                packageName = this fullName substring(0, idx)
        }

        underName = sanitize(this fullName clone())
        packageName = sanitize(packageName)
    }

    getLoadFuncName: func -> String { getUnderName() + "_load" }
    getFullName:     func -> String { fullName }
    getUnderName:    func -> String { underName }
    getPathElement:  func -> String { pathElement }
    getSourceFolderName: func -> String {
        File new(File new(getPathElement()) getAbsolutePath()) name()
    }
    
    collectDeps: func -> List<Module> {
        _collectDeps(ArrayList<Module> new())
    }
    
    _collectDeps: func (list: List<Module>) -> List<Module> {
        list add(this)
		for(imp in getAllImports()) {
			if(!list contains(imp getModule())) {
				imp getModule() _collectDeps(list)
			}
		}
        list
    }

    addFuncType: func (hashName: String, funcType: FuncType) {
        if(!funcTypesMap contains(hashName)) {
            funcTypesMap put(hashName, funcType)
        }
    }

    sanitize: func(str: String) -> String {
        result := str clone()
        for(i in 0..result length()) {
            current := result[i]
            if(!current isAlphaNumeric()) {
                result[i] = '_'
            }
        }
        if(!result[0] isAlpha()) result = '_' + result
        result
    }

    addFunction: func (fDecl: FunctionDecl) {
        functions put(TypeDecl hashName(fDecl), fDecl)
    }

    addType: func (tDecl: TypeDecl) {
        old := types get(tDecl name) as TypeDecl
        if(old != null) {
            tDecl token printMessage("Redefinition of type %s" format(tDecl name), "[ERROR]")
            old   token throwError("...first definition was here: ")
        }
        
        types put(tDecl name, tDecl)
        if(tDecl getMeta()) types put(tDecl getMeta() name, tDecl getMeta())
    }

    addOperator: func (oDecl: OperatorDecl) {
        operators add(oDecl)
    }

    addImport: func (imp: Import) {
        imports add(imp)
    }

    addInclude: func (inc: Include) {
        includes add(inc)
    }

    addNamespace: func (nDecl: NamespaceDecl) {
        namespaces put(nDecl getName(), nDecl)
    }<commit_msg>Throw an error on function redefinition. Closes #37<commit_after>import io/File, text/EscapeSequence
import structs/[HashMap, ArrayList, List, OrderedMultiMap]
import ../frontend/[Token, SourceReader, BuildParams, PathList, AstBuilder]
import ../utils/FileUtils
import Node, FunctionDecl, Visitor, Import, Include, Use, TypeDecl,
       FunctionCall, Type, Declaration, VariableAccess, OperatorDecl,
       Scope, NamespaceDecl, BaseType, FuncType
import tinker/[Response, Resolver, Trail]

Module: class extends Node {

    timesImported := 0
    timesLooped := 0

    path, fullName, simpleName, packageName, underName, pathElement : String
    main := false

    types      := OrderedMultiMap<String, TypeDecl> new()
    functions  := OrderedMultiMap<String, FunctionDecl> new()
    operators  := ArrayList<OperatorDecl> new()

    includes   := ArrayList<Include> new()
    imports    := ArrayList<Import> new()
    namespaces := HashMap<String, NamespaceDecl> new()
    uses       := ArrayList<Use> new()

    funcTypesMap := HashMap<String, FuncType> new()

    body       := Scope new()

    lastModified : Long

    params: BuildParams
    
    init: func ~module (.fullName, =pathElement, =params, .token) {
        super(token)
        this path = fullName clone() replace('/', File separator)
        this fullName = fullName replace(File separator, '/')
        idx := this fullName lastIndexOf('/')

        match idx {
            case -1 =>
                simpleName = this fullName clone()
                packageName = ""
            case =>
                simpleName = this fullName substring(idx + 1)
                packageName = this fullName substring(0, idx)
        }

        underName = sanitize(this fullName clone())
        packageName = sanitize(packageName)
    }

    getLoadFuncName: func -> String { getUnderName() + "_load" }
    getFullName:     func -> String { fullName }
    getUnderName:    func -> String { underName }
    getPathElement:  func -> String { pathElement }
    getSourceFolderName: func -> String {
        File new(File new(getPathElement()) getAbsolutePath()) name()
    }
    
    collectDeps: func -> List<Module> {
        _collectDeps(ArrayList<Module> new())
    }
    
    _collectDeps: func (list: List<Module>) -> List<Module> {
        list add(this)
		for(imp in getAllImports()) {
			if(!list contains(imp getModule())) {
				imp getModule() _collectDeps(list)
			}
		}
        list
    }

    addFuncType: func (hashName: String, funcType: FuncType) {
        if(!funcTypesMap contains(hashName)) {
            funcTypesMap put(hashName, funcType)
        }
    }

    sanitize: func(str: String) -> String {
        result := str clone()
        for(i in 0..result length()) {
            current := result[i]
            if(!current isAlphaNumeric()) {
                result[i] = '_'
            }
        }
        if(!result[0] isAlpha()) result = '_' + result
        result
    }

    addFunction: func (fDecl: FunctionDecl) {
        hash := TypeDecl hashName(fDecl)
        old := functions get(hash)
        if (old != null) {
            "Old token = (%d, %d)" printfln(old token start, old token length)
            fDecl token printMessage("Redefinition of '%s'" format(old getName(), fullName), "[ERROR]")
            old   token throwError("...first definition was here: ")
        }
        functions put(hash, fDecl)
    }

    addType: func (tDecl: TypeDecl) {
        old := types get(tDecl name) as TypeDecl
        if (old != null) {
            tDecl token printMessage("Redefinition of '%s'" format(tDecl name), "[ERROR]")
            old   token throwError("...first definition was here: ")
        }
        
        types put(tDecl name, tDecl)
        if(tDecl getMeta()) types put(tDecl getMeta() name, tDecl getMeta())
    }

    addOperator: func (oDecl: OperatorDecl) {
        operators add(oDecl)
    }

    addImport: func (imp: Import) {
        imports add(imp)
    }

    addInclude: func (inc: Include) {
        includes add(inc)
    }

    addNamespace: func (nDecl: NamespaceDecl) {
        namespaces put(nDecl getName(), nDecl)
    }
{'fraction_non_alphanumeric': 0.11575887779603185, 'fraction_numerical': 0.0020219891318084167, 'mean_word_length': 2.4053356282271947, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2336349', 'n_tokens_mistral': 2342, 'n_tokens_neox': 2245, 'n_words': 622}