RrunningW```
fed619ab创建于 2025年12月6日历史提交
/*
Copyright (c) 2025 WuJingrun(吴京润)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
macro package f_aspect.macros

import std.ast.*
import f_aspect.exception.AspectException
import f_macros.*
import std.reflect.*

public macro Pointcut(input: Tokens): Tokens {
    if (insideParentContext('Pointcut')) {
        return input
    }
    func doPointcut(decl: Decl): Tokens {
        match(decl){
            case x: FuncDecl => pointcut(x)
            case x: ClassDecl => pointcut(x)
            case x: MacroExpandDecl =>
                var m: MacroExpandDecl = x
                while(let md: MacroExpandDecl <- m.macroInputDecl){
                    m = md
                }
                m.macroInputDecl = parseDecl(doPointcut(m.macroInputDecl))
                x.toTokens()
            case x => 
                diagReport(ERROR, input, '${x.identifier.value} must be a func decl or a class decl', '')
                throw AspectException()
        }
    }
    doPointcut(parseDecl(input))
}
func pointcut(decl: FuncDecl): Tokens {
    var tokens = decl.toTokens()
    var funcDecl = quote()
    for (t in tokens) {
        if (t.kind == TokenKind.LCURL) {
            break
        }
        funcDecl += t
    }
    let params = decl.funcParams
    var argVars = quote()
    var args = `lsquare`
    var argTypes = `lsquare`
    for (i in 0..params.size) {
        let param = match(params[i]){
            case x: MacroExpandParam => 
                var mp: MacroExpandParam = x
                while(let m: MacroExpandParam <- mp.macroInputDecl){
                    mp = m
                }
                match(mp.macroInputDecl){
                    case x: FuncParam => x
                    case x: MacroExpandDecl => 
                        var md: MacroExpandDecl = x
                        while(let m: MacroExpandDecl <- md.macroInputDecl){
                            md = m
                        }
                        match(md.macroInputDecl){
                            case x: FuncParam => x
                            case x => FuncParam(x.toTokens())
                        }
                    case x => throw AspectException('unexpected decl ${x.toTokens()} ${ClassTypeInfo.of(x)}')
                }
            case x: FuncParam => x
            case x => throw AspectException('unexpected decl ${x.toTokens()} ${ClassTypeInfo.of(x)}')
        }
        let paramName = param.identifier
        argVars += quote(
            let $paramName = (args[$(i)] as $(param.paramType)).getOrThrow()
        ) + `nl`
        if (i > 0) {
            args += `comma`
            argTypes += `comma`
        }
        args += paramName
        argTypes += quote(TypeInfo.of<$(param.paramType)>())
    }
    args += `rsquare`
    argTypes += `rsquare`
    let funcName = decl.identifier.value
    let funcType = try {
        decl.declType.toTokens()
    } catch (_) {
        `empty_tokens`
    }
    let proceed = if (funcType.size == 0) {
        quote(Aspects.proceed(info, callee))
    } else {
        quote(Aspects.proceed<$funcType>(info, callee))
    }
    tokens = quote(
        $funcDecl {
            func callee(args: Array<Any>){
                $argVars
                $(decl.block.nodes)
            }
            let info = InvocationFuncInfo(TypeInfo.of(this), $funcName, $argTypes, $args)
            $proceed
        }
    )
    tokens
}
private func pointcut(decl: ClassDecl): Tokens {
    let decls = decl.body.decls
    for(i in 0 .. decls.size) {
        let d = decls[i]
        if (let f: FuncDecl <- d && !isStatic(d) && isPublic(d) && d.identifier.value != 'init') {
            decls[i] = parseDecl(pointcut(f))
        } else if (let md: MacroExpandDecl <- d) {
            var m: MacroExpandDecl = md
            while(let md: MacroExpandDecl <- m.macroInputDecl){
                m = md
            }
            if(let f: FuncDecl <- m.macroInputDecl && !isStatic(f) && isPublic(f)){
                m.macroInputDecl = parseDecl(pointcut(f))
            }
        }
    }
    decl.toTokens()
}